OPERATOR OVERLOADING
The example file named OPOVERLD.CPP contains examples of overloading operators.
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 | // opoverld.cpp #include <iostream.h> class box { int length; int width; public: void set(int l, int w) {length = l; width = w;} int get_area(void) {return length * width;} friend box operator+(box a, box b); // Add two boxes friend box operator+(int a, box b); // Add a constant to a box friend box operator*(int a, box b); // Multiply a box by a constant }; box operator+(box a, box b) // Add two boxes' widths together { box temp; temp.length = a.length; temp.width = a.width + b.width; return temp; } box operator+(int a, box b) // Add a constant to a box { box temp; temp.length = b.length; temp.width = a + b.width; return temp; } box operator*(int a, box b) // Multiply a box by a constant { box temp; temp.length = a * b.length; temp.width = a * b.width; return temp; } main() { box small, medium, large; box temp; small.set(2, 4); medium.set(5, 6); large.set(8, 10); cout << "The area is " << small.get_area() << "\n"; cout << "The area is " << medium.get_area() << "\n"; cout << "The area is " << large.get_area() << "\n"; temp = small + medium; cout << "The new area is " << temp.get_area() << "\n"; temp = 10 + small; cout << "The new area is " << temp.get_area() << "\n"; temp = 4 * large; cout << "The new area is " << temp.get_area() << "\n"; } // Result of Execution // // The area is 8 // The area is 30 // The area is 80 // The new area is 20 // The new area is 28 // The new area is 1280 |
This allows you to define a class of objects and redefine the use of the normal operators. The end result is that objects of the new class can be used in as natural a manner as the predefined types. In fact, they seem to be a part of the language rather than your own add-on.
In this case we overload the + operator and the * operator, with the declarations in lines 10 through 12, and the definitions in lines 16 through 40. The methods are declared as friend functions so we can use the double parameter functions as listed. If we did not use the friend construct, the function would be a part of one of the objects and that object would be the object to which the message was sent. Including the friend construct allows us to separate this method from the object and call the method with infix notation. Using this technique, it can be written as object1 + object2 rather than object1.operator+(object2). Also, without the friend construct we could not use an overloading with an int type variable for the first parameter because we can not send a message to an integer type variable such as int.operator+(object). Two of the three operator overloadings use an int for the first parameter so it is necessary to declare them as friend functions.
There is no upper limit to the number of overloadings for any given operator. Any number of overloadings can be used provided the parameters are different for each particular overloading.
The header in line 16 illustrates the first overloading where the + operator is overloaded by giving the return type followed by the keyword operator and the operator we wish to overload. The two formal parameters and their types are then listed in the parentheses and the normal function operations are given in the implementation of the function in lines 18 through 21. The observant student will notice that the implementation of the friend functions are not actually a part of the class because the class name is not prepended onto the method name in line 16. There is nothing unusual about this implementation, it should be easily understood by you at this point. For purposes of illustration, some silly mathematics are performed in the method implementation, but any desired operations can be done
The biggest difference occurs in line 56 where this method is called by using the infix notation instead of the usual message sending format. Since the variables small and medium are objects of the box class, the system will search for a way to use the + operator on two objects of class box and will find it in the overloaded operator+ method we have just discussed. The operations within the method implementation can be anything we need them to be, and they are usually much more meaningful than the silly math included here.
In line 58 we ask the system to add an int type constant to an object of class box, so the system finds the other overloading of the + operator beginning in line 25 to perform this operation. Also in line 60 we ask the system to use the * operator to do something to an int constant and an object of class box, which it satisfies by finding the method in lines 34 through 40. Note that it would be illegal to attempt to use the * operator the other way around, namely large * 4 since we did not define a method to use the two types in that order. Another overloading could be given with reversed types, and we could use the reverse order in a program.
You will notice that when using operator overloading, we are also using function name overloading since some of the function names are the same.
When we use operator overloading in this manner, we actually make our programs look like the class is a natural part of the language since it is integrated into the language so well. C++ is therefore an extendible language and can be molded to fit the mechanics of the problem at hand.
OPERATOR OVERLOADING CAVEATS
Each new topic we study has its pitfalls which must be warned against and the topic of operator overloading seems to have the record for pitfalls since it is so prone to misuse and has several problems. The overloading of operators is only available for classes, you cannot redefine the operators for the predefined simple types. This would probably be very silly anyway since the code could be very difficult to read if you changed some of them around.
The logical and (&&) and the logical or (||) operators can be overloaded for the classes you define, but they will not operate as short circuit operators. All members of the logical construction will be evaluated with no regard concerning the outcome. Of course the normal predefined logical operators will continue to operate as short circuit operators as expected, but not the overloaded ones.
If the increment (++) or decrement (–) operators are overloaded, the system has no way of telling whether the operators are used as preincrement or postincrement (or predecrement or postdecrement) operators. Which method is used is implementation dependent, so you should use them in such a way that it doesn’t matter which is used.
Be sure to compile and execute OPOVERLD.CPP before continuing on to the next example program.