This is a continuation from the previous Module. The source code for this tutorial is available in C++ Data Encapsulation source code.
Able to understand and use:
|
|
13.12 Operator Overloading
1. // program opverlod.cpp, operator overloading 2. #include <iostream> 3. using namespace std; 4. 5. // a class declaration part 6. class wall 7. { 8. public: 9. int length; 10. int width; 11. 12. public: 13. void set(int l, int w) {length = l; width = w;} 14. int get_area(void) {return length * width;} 15. // operator overloading 16. friend wall operator + (wall aa, wall bb); // add two walls 17. friend wall operator + (int aa, wall bb); // add a constant to a wall 18. friend wall operator * (int aa, wall bb); 19. // multiply a wall by a constant 20. }; 21. 22. // class implementation part 23. wall operator + (wall aa, wall bb) 24. // add two walls widths together 25. { 26. wall temp; 27. temp.length = aa.length; 28. temp.width = aa.width + bb.width; 29. return temp; 30. } 31. 32. wall operator + (int aa, wall bb) 33. // add a constant to wall 34. { 35. wall temp; 36. temp.length = bb.length; 37. temp.width = aa + bb.width; 38. return temp; 39. } 40. 41. wall operator * (int aa, wall bb) 42. // multiply wall by a constant 43. { 44. wall temp; 45. temp.length = aa * bb.length; 46. temp.width = aa * bb.width; 47. return temp; 48. } 49. 50. void main() 51. { 52. wall small, medium, large; //object instances 53. wall temp; 54. 55. small.set(2,4); 56. medium.set(5,6); 57. large.set(8,10); 58. 59. cout<<"Normal values\n"; 60. cout<<"-------------\n"; 61. cout<<"Area of the small wall surface is "<<small.get_area()<<"\n"; 62. cout<<"Area of the medium wall surface is "<<medium.get_area()<<"\n"; 63. cout<<"Area of the large wall surface is "<<large.get_area()<<"\n\n"; 64. cout<<"Overload the operators!"<<"\n"; 65. cout<<"-----------------------"<<endl; 66. temp = small + medium; 67. cout<<"New value-->2 * (4 + 6)\n"; 68. cout<<"New area of the small wall surface is "<<temp.get_area()<<"\n\n"; 69. cout<<"New value-->2 * (10 + 4) \n"; 70. temp = 10 + small; 71. cout<<"New area of the medium wall surface is "<<temp.get_area()<<"\n\n"; 72. cout<<"New value-->(4 * 8) * (4 * 10)\n"; 73. temp = 4 * large; 74. cout<<"New area of the large wall surface is "<<temp.get_area()<<"\n\n"; 75. 76. // system("pause"); 77. }
|

The end result is that objects of the new class can be used in as natural 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 16 through 18 as shown below, and the definitions in lines 23 through 47. The methods are declared as friend functions, so we can use the double parameter function as listed.
If we do 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.
friend wall operator + (wall aa, wall bb); // add two walls
friend wall operator + (int aa, wall bb); // add a constant to a wall
friend wall operator * (int aa, wall bb);
By 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 operators overloading 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 overloading for any given operator. Any number of overloading can be used provided the parameters are different for each particular overloading.
As shown below, the header in line 23, 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.
wall operator + (wall aa, wall bb)
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 functions in lines 25 through 30 as shown below.
Notice that the implementation of the friend functions is not actually a part of the class because the class name is not prepended onto the method name in line 22.
{
wall temp;
temp.length = aa.length;
temp.width = aa.width + bb.width;
return temp;
}
There is nothing unusual about this implementation; it should be easily understood by you at this point. For purposes of illustration, some simple mathematical operations are performed in the method implementation, but any desired operations can be done.
The biggest difference occurs in line 65 as shown below where this method is called by using the infix notation instead of the usual message sending format.
temp = small + medium;
-------------------------------------------------------------------------------------------------------------------------
Infix Expression: Any expression in the standard form such as "4*2-6/3" is an Infix (In order) expression.
Postfix Expression: The Postfix (Post order) form of the above expression is "42*63/-".
--------------------------------------------------------------------------------------------------------------------------
Since the small and medium variables are objects of the wall class, the system will search for a way to use the + operator on two objects of wall class and will find it in the overloaded operator + method we have just discussed.
In line 70 as shown below, we ask the system to add an int type constant to a small object of class wall, so the system finds the other overloading of the + operator beginning in line 31 through 38 to perform this operation.
temp = 10 + small;
In line 72 as shown below, we ask the system to use the * operator to do something to an int constant and a large object of class wall, which it satisfies by finding the method in lines 40 through 47.
temp = 4 * large;
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 then use the reverse order in a program.
You will notice that when using operator overloading, we are also using function name overloading (function overloading) since some of the function names are 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.
Each new part we study has its pitfalls which must be warned against and the part 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 basic data types.
The preprocessing symbols # and ## cannot be overloaded.
The =, [ ], ( ), and → operators can be overloaded only as non-static member functions. These operators cannot be overloaded for enum types. Any attempt to overload a global version of these operators results in a compile-time error.
The keyword operator followed by the operator symbol is called the operator function name; it is used like a normal function name when defining a new (overloaded) action for the operator.
The operator function cannot alter the number of arguments or the precedence and associativity rules applying to normal operator use.
Table 13.1 and 13.2 list the operators that can be overloaded and cannot be overloaded respectively.
Which method is used is implementation dependent, so you should use them in such a way that it doesn’t matter which is used. Compile and run the program opverlod.cpp before continuing on the next program example.
------------------------------------------------------
|
Operators |
||||
|
+ |
- |
* |
/ |
% |
|
^ |
& |
| |
~ |
! |
|
= |
< |
> |
+= |
-= |
|
*= |
/= |
%= |
^= |
&= |
|
|= |
<< |
>> |
>>= |
<<= |
|
== |
!= |
<= |
>= |
&& |
|
|| |
++ |
-- |
->* |
, |
|
→ |
[ ] |
( ) |
new |
delete |
|
Table 13.1: Operators that can be overloaded |
||||
|
Operators |
|||
|
. |
.* |
?: |
:: |
|
Table 13.2: Operators that cannot be overloaded |
|||
Examine the program named funovlod.cpp. This is an example of function name overloading within a class. In this program, the constructor is overloaded as well as one of the methods to illustrate what can be done.
1. // program funovlod.cpp, function overloading
2. #include <iostream>
3. using namespace std;
4.
5. // a class declaration part
6. class many_names
7. {
8. int length;
9. int width;
10. public:
11. many_names(void);
12. many_names(int len);
13. many_names(int len, int wid);
14. // constructors with different number and type
15. // of parameter list – overloaded functions
16. void display(void);
17. void display(int one);
18. void display(int one, int two);
19. void display(float number);
20. // methods with different number and type
21. // of parameter list – overloaded functions
22. };
23.
24. // implementation part
25. many_names::many_names(void) // void
26. {
27. length = 8;
28. width = 8;
29. }
30.
31. many_names::many_names(int len) // one parameter
32. {
33. length = len;
34. width = 8;
35. }
36.
37. many_names::many_names(int len, int wid) // two parameter
38. {
39. length = len;
40. width = wid;
41. }
42.
43. void many_names::display(void) // void for display
44. {
45. cout<<"From void display function, Area = "<<length * width<<"\n";
46. }
47.
48. void many_names::display(int one) // 1 parameter
49. {
50. cout<<"From int display function, Area = "<<length * width<<"\n";
51. }
52.
53. void many_names::display(int one, int two) // 2 parameters
54. {
55. cout<<"From two int display function, Area = "<<length * width<<"\n";
56. }
57.
58. void many_names::display(float number) //1 parameter
59. {
60. cout<<"From float display function, Area = "<<length * width<<"\n";
61. }
62.
63. // the main program
64. main()
65. {
66. many_names small, medium(10), large(12,15);
67. int gross = 144;
68. float pi = 3.1415, payroll = 12.50;
69.
70. cout<<"Guess, which function that they invoked???\n";
71. cout<<"------------------------------------------\n";
72. cout<<"-->small.display()\n";
73. small.display();
74. cout<<"\n-->small.display(100)\n";
75. small.display(100);
76. cout<<"\n-->small.display(gross,100)\n";
77. small.display(gross,100);
78. cout<<"\n-->small.display(payroll)\n";
79. small.display(payroll);
80. cout<<"\n-->medium.display()\n";
81. medium.display();
82. cout<<"\n-->large.display(pi)\n";
83. large.display(pi);
84.
85. // system("pause");
86. }

many_names small, medium(10), large(12, 15);
|
As many overloading as desired can be used provided that all of the parameter patterns are unique.
Other example is the << operator which is part of the cout class, which operates as an overloaded function since the way it outputs data is a function of the type of its input variable or the field we ask it to display.
Many programming languages have overloaded functions so you can output any data with the same function name. Compile and run this program.
Examine the program deftmeth.cpp carefully, illustrating those methods provided by the compiler, and why you sometimes can’t use the defaults but need to write your own, to do the job the defaults were intended to do for you.
1. // program deftmeth.cpp, default method
2.