February 27, 2002 Reading assignment: Deitel and Deitel - 8.1-8.3 and 8.7-8.8 -or- Other texts: overloading binary operators, the copy constructor Warm-up: I'll hand back exams and we'll do the last problem together Why do we want/need to overload operators? Some examples: - If we have two strings, s1 and s2, we can say if (s1==s2) cout << s1; or cout << s[0]; We can do this because the string class "overloaded" the operators ==, <<, and []. In other words, the string class includes code that says what to do if you use ==, <<, or [] with strings. This makes the string class useful - We wrote a class called Ratnum. Say if have two Ratnum objects, r1 and r2 If I write any of the following if (!r1) cout < "urp"; if (r1 == r2) cout << "yah, man"; r1 = r1 + r2; r1 += r2; cout << r1 << r2; the compiler will give me an error. Why? Because we did not overload the ! operator, the + operator, += operator, << or >>. This severely limits the usefulness of our Ratnum class. - On the other hand, if we say r1 = r2; the compiler will not complain, even though we didn't overload the assignment operator! The compiler always creates a default assignment operator for a class, which just copies all the data members. This can be an advantage because it saves us from overloading the assignment operator, but if member-wise copy is not what we want, then we'd better overload the assignment operator to do what we want. If our class contains pointer data members, then we almost always want to do this. - Another default function the compiler provides for classes is a default copy constructor. This does a memberwise copy. The copy constructor gets called whenever you initialize an object to be a copy of an existing object of the same class, whenever an object is sent as a parameter to a function, and whenever an object is returned by a function. If our class contains pointer data members, then we don't want to use the default copy constructor, and we must override it. - Some of the operators we need to overload (such as !) are unary operators (they operate on only one value), and others are binary operators (such as +, ==, or =) which operate on two values. The syntax for these two cases is slightly different. Today we'll learn how to overload binary operators. See your text for a list of all operators that you may overload. - Let's start with overloading the operator + and == (because they're easier than overloading =) The first thing you need to know is that if x and y are objects of type class fooclass, and if you say x + y, the compiler secretly thinks of it as x.operator+(y), where operator+ is a member function of fooclass. Now guess what it does with (x==y). (x.operator==(y)). So all we need to make such a member function (it can also be done with a friend function - read about it and you're free to do it that way instead) Notice that we use the member function for the left-hand operand - Let's overload the + and == operators for a class of complex numbers class Complex { public: Complex(float r=0, float i=0) {real=r, imag = i;} void display() const {cout << real << " + " << imag << "i ";} void set_real(float r, float im) { real = r; imag = im;} Complex operator+(const Complex &c); bool operator==(const Complex &c) const {return (c.real==real &&c.imag==imag);}; private: float real; float imag; }; Complex Complex::operator+(const Complex &c) { Complex ans; ans.real = real+c.real; ans.imag = imag+c.imag; return ans; } int main() { Complex c1(2), c2(2,4), c4(2, 4), c3; cout << "Testing the + operator: " << endl; c3 = c1+c2; c1.display(); cout << " + "; c2.display(); cout << " = "; c3.display(); cout << endl; if (c4==c2) cout << "Yeah! == works! " << endl; if (!(c1==c2)) cout << "Yeah! == works" << endl; return 0; }