Overloaded Operators

I'm implementing a rational number class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <iostream>
#include <stdint.h>
using namespace std;

typedef int64_t RAT_INT;
struct RAT{
	RAT_INT Num, Den;

	RAT(RAT_INT num = 0, RAT_INT den = 1){
		Num = num;
		Den = den;
	}

	template <class T>
	T Real(){
		return (T)Num/Den;
	}

	RAT_INT Gcd(){
		RAT_INT num = Num, den = Den;
		while(num){
			RAT_INT tmp;
			tmp = num;
			num = den % num;
			den = tmp;
		}
		return den;
	}

	RAT Red(){
		RAT_INT div = Gcd();
		return RAT(Num / div, Den / div);
	}
	RAT Reda(){
		return *this = Red();
	}

	RAT Sq(){
		return *this * *this;
	}
	RAT Sqa(){
		return *this = Sq();
	}

	bool operator== (RAT rat){
		return Num*rat.Den == rat.Num*Den;
	}
	bool operator!= (RAT rat){
		return !(*this == rat);
	}
	bool operator> (RAT rat){
		if((Den >= 0 && rat.Den >= 0) ||
		   (Den <  0 && rat.Den <  0)){
			return Num*rat.Den > rat.Num*Den;
		}else{
			return Num*rat.Den < rat.Num*Den;
		}
	}
	bool operator< (RAT rat){
		return rat > *this;
	}
	bool operator>= (RAT rat){
		return !(*this < rat);
	}
	bool operator<= (RAT rat){
		return !(*this > rat);
	}

/*
	RAT operator= (RAT_INT i){
		return *this = RAT(i);
	}
*/

	RAT operator- (){
		return RAT(-Num, Den);
	}
	RAT Rec(){
		return RAT(Den, Num);
	}

	RAT operator+ (RAT rat){
		return RAT(Num*rat.Den + rat.Num*Den, Den*rat.Den).Red();
	}
	RAT operator- (RAT rat){
		return *this + -rat;
	}
	RAT operator* (RAT rat){
		return RAT(Num * rat.Num, Den * rat.Den).Red();
	}
	RAT operator/ (RAT rat){
		return *this * rat.Rec();
	}

	RAT operator+= (RAT rat){
		return *this = *this + rat;
	}
	RAT operator-= (RAT rat){
		return *this = *this - rat;
	}
	RAT operator*= (RAT rat){
		return *this = *this * rat;
	}
	RAT operator/= (RAT rat){
		return *this = *this / rat;
	}
};

std::ostream& operator<< (std::ostream& os, RAT rat){
	return os << rat.Num << "/" << rat.Den;
}

int main(){
	cout << 1 + 2 << endl;
	cout << RAT(1) + 2 << endl;
//	cout << 1 + RAT(2) << endl;
	return 0;
}
3
3/1
Two questions:
1) In the second line in main, how does C++ know to convert 2 to the appropriate RAT?
2) Is it possible to make the third line in main valid without adding global operators for all the member operators to support plain integers?
Last edited on
1) In the second line in main, how does C++ know to convert 2 to a the appropriate RAT?


The constructor on line 9 isn't marked as explicit so it may be used to convert the second argument to operator+ to a RAT without an explicit cast.

2) Is it possible to make the third line in main valid without adding global operators for all the member operations to support plain integers?


Nope. I would've made every member function a non-member function, anyway, with the exception of the constructor.
I would've made every member function a non-member function, anyway, with the exception of the constructor.


Why's that? I thought the point of classes was to include member functions to remove the redundancy of functions with struct arguments.
Why's that? I thought the point of classes was to include member functions to remove the redundancy of functions with struct arguments.


No. That doesn't even play into the "point" of classes. Every class function has a "hidden" pointer argument which you may refer to inside the function as this.

The point of classes is to encapsulate data and the functions which manipulate it. When all of your data is public, there is no encapsulation (and no need for member functions.) Were the data not public, you would want to limit the number of member functions to as few as possible, so that those functions that needn't be member functions (or, in other words, could be implemented in terms of other member functions) don't have access to private data.

Would it make sense to have to add a new operator<< overload to the std::ostream class everytime we needed to overload it for a new class?
I use member functions simply for convenience; it's less typing. I think programming should take into consideration some aspect of convenience. I see no reason why it'd be more better to make the functions global, as these operations are directly involved with the RAT class. You talk about limiting the number of member functions, but I don't see why.

It wouldn't make sense to add a new operator+ overload to RAT when I wanted to overload it for a new class either, so in that case I'd define a global operator.
You talk about limiting the number of member functions, but I don't see why.


You might find the following to be interesting reading:

http://www.codeproject.com/Articles/4534/Non-Member-Functions-in-OOP
http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197
Topic archived. No new replies allowed.