In the previous page, we made the addition operator a member of the class Complex. Now let's implement
the same functionality using a global function. Since this function will need to access the private members
of Complex, we'll need to declare it as a friend function.
class Complex {
private:
double real, imag;
public:
Complex() { real = imag = 0; }
Complex(double r, double i) { real = r; imag = i; }
double GetReal(void) const { return real; }
double GetImag(void) const { return imag; }
Complex& operator=(const Complex& num);
Complex& operator=(const double& d);
friend const Complex operator+(const Complex& first, const Complex& second);
};
Note the friend keyword. This is needed so that the global function can access the real and imag
member variables. The global function is implemented as follows:
const Complex operator+(const Complex& first, const Complex& second) {
Complex tmp;
tmp.real = first.real + second.real;
tmp.imag = first.imag + second.imag;
return tmp;
}
You are invited to test drive this new implementation of the + operator to convince yourself that it
does the same thing as the operator in the previous page.
NOTE: If you don't like to use the friend keyword, you could implement public SetReal() and SetImag() functions
to access the real and imag members of class Complex. In this case, the code would look like this:
class Complex {
private:
double real, imag;
public:
Complex() { real = imag = 0; }
Complex(int r, int i) { real = r; imag = i; }
double GetReal(void) const { return real; }
double GetImag(void) const { return imag; }
Complex& operator=(const Complex& num);
Complex& operator=(const double& d);
void SetReal(double r) { real = r; }
void SetImag(double i) { imag = i; }
// friend declaration removed.
};
const Complex operator+(const Complex& first, const Complex& second); // function prototype
...
...
const Complex operator+(const Complex &first, const Complex& second) {
Complex tmp;
tmp.SetReal(first.GetReal() + second.GetReal());
tmp.SetImag(first.GetImag() + second.GetImag());
return tmp;
}
Irrespective of whether we use the first or second implementation, notice that the global function does the same thing as
the class member function we implemented in the previous page. So why did we go through the trouble of using
a global function then? You'll see in just a little bit.
Consider the case where we want to add a Complex number and a double. We can easily implement
this as follows:
class Complex {
private:
double real, imag;
public:
Complex() { real = imag = 0; }
....
const Complex operator+(const double& d) const;
};
const Complex Complex::operator+(const double& d) const {
Complex tmp;
tmp.real = real + d;
return tmp;
}
int main(void) {
Complex num1(2, 3);
double d = 24.34;
Complex num2;
num2 = num1 + d;
cout << "num2 is " << num2.GetReal() << " + "
<< num2.GetImag() << "i" << endl;
return 0;
}
This works pretty well, until we try to do this:
num2 = num1 + d; // WORKS
num2 = d + num1; // DOESN'T WORK
Suddenly this code doesn't work if the double is the first number. The reason for this is because
when we defined the operator overload, it expects the first variable of the addition operator to
be of class Complex. There isn't an operator defined yet that takes a double as the first parameter.
As it happens, we cannot write this as a member function of class Complex. So what do we do then?
The answer is, we need to write a global function that takes a double as the first argument and a complex
as the second argument. Now you can see why we studied overloading with global functions at the top of
this section.
const Complex operator+(const double& first, const Complex& second) {
return second + first;
}
Bet that was more trivial than you expected. Notice that the global function doesn't do much at all.
All it does is reverse the order of the
operands. Since we've already defined the operation for Complex + double, the global function
merely reuses that code to its advantage to define double + Complex. Also note that this global function
didn't need to be declared as friend, since it doesn't need to access any of class Complex's private
members. Hence, there is no need to alter the definition of the Complex class. With this function, we can now do:
Complex num1(5, 2), num2;
double d = 24.5;
num2 = num1 + d; // WORKS
num2 = d + num1; // ALSO WORKS NOW
Now you can practice your skills by overloading some other operators. In the next section, we will
study how to overload increment and decrement operators.
Exercises
1. Overload the subtraction operator (-) between a Complex and a double and double and Complex.
2. Overload the multiplication operator (*) for Complex numbers. HINT: For multiplication, the
operation is as follows:
tmp.real = first.real * second.real - first.imag * second.imag;
tmp.imag = first.real * second.imag + second.real * first.imag;