C++

Operator Overloading Unary Operators

Declare an overloaded operator as you would a function. Use the keyword operator, followed by the operator to overload. Unary operator functions do not take parameters, with the exception of the postfix increment and decrement, which take an integer as a flag. Example 1

const Counter& Counter::operator++ ();

Example 2

Counter Counter::operator-(int);

DO use a parameter to operator++ if you want the postfix operator. DO return a const reference to the object from operator++. DON’T create temporary objects as return values from operator++.

The Addition Operator

The increment operator is a unary operator. It operates on only one object. The addition operator (+) is a binary operator, where two objects are involved. How do you implement overloading the + operator for Count?

The goal is to be able to declare two Counter variables and then add them, as in this example:

Counter varOne, varTwo, varThree;

VarThree = VarOne + VarTwo;

Once again, you could start by writing a function, Add(), which would take a Counter as its argument, add the values, and then return a Counter with the result. Listing 10.13 illustrates this approach.

Listing 10.13. The Add() function.

1: // Listing 10.13

2: // Add function

3:

4: typedef unsigned short USHORT;

5: #include <iostream.h>

6:

7: class Counter

8: {

9: public:

10: Counter();

11: Counter(USHORT initialValue);

12: ~Counter(){}

13: USHORT GetItsVal()const { return itsVal; }

14: void SetItsVal(USHORT x) {itsVal = x; }

15: Counter Add(const Counter &);

16:

17: private:

18: USHORT itsVal;

19:

20: };

21:

22: Counter::Counter(USHORT initialValue):

23: itsVal(initialValue)

24: {}

25:

26: Counter::Counter():

27: itsVal(0)

28: {}

29:

30: Counter Counter::Add(const Counter & rhs)

31: {

32: return Counter(itsVal+ rhs.GetItsVal());

33: }

34:

35: int main()

36: {

37: Counter varOne(2), varTwo(4), varThree;

38: varThree = varOne.Add(varTwo);

39: cout << "varOne: " << varOne.GetItsVal()<< endl;

40: cout << "varTwo: " << varTwo.GetItsVal() << endl;

41: cout << "varThree: " << varThree.GetItsVal() << endl;

42:

43: return 0;

44: }

OUTPUT:

varOne: 2

varTwo: 4

varThree: 6

Analysis: The Add()function is declared on line 15. It takes a constant Counter reference, which is the number to add to the current object. It returns a Counter object, which is the result to be assigned to the left side of the assignment statement, as shown on line 38. That is, VarOne is the object, varTwo is the parameter to the Add() function, and the result is assigned to VarThree.

In order to create varThree without having to initialize a value for it, a default constructor is required. The default constructor initializes itsVal to 0, as shown on lines 26-28. Since varOne and varTwo need to be initialized to a non-zero value, another constructor was created, as shown on lines 22-24. Another solution to this problem is to provide the default value 0 to the constructor declared on line 11.

Overloading operator+

The Add() function itself is shown on lines 30-33. It works, but its use is unnatural. Overloading the + operator would make for a more natural use of the Counter class. Listing 10.14 illustrates this.

Listing 10.14. operator+.

1: // Listing 10.14

2: //Overload operator plus (+)

3:

4: typedef unsigned short USHORT;

5: #include <iostream.h>

6:

7: class Counter

8: {

9: public:

10: Counter();

11: Counter(USHORT initialValue);

12: ~Counter(){}

13: USHORT GetItsVal()const { return itsVal; }

14: void SetItsVal(USHORT x) {itsVal = x; }

15: Counter operator+ (const Counter &);

16: private:

17: USHORT itsVal;

18: };

19:

20: Counter::Counter(USHORT initialValue):

21: itsVal(initialValue)

22: {}

23:

24: Counter::Counter():

25: itsVal(0)

26: {}

27:

28: Counter Counter::operator+ (const Counter & rhs)

29: {

30: return Counter(itsVal + rhs.GetItsVal());

31: }

32:

33: int main()

34: {

35: Counter varOne(2), varTwo(4), varThree;

36: varThree = varOne + varTwo;

37: cout << "varOne: " << varOne.GetItsVal()<< endl;

38: cout << "varTwo: " << varTwo.GetItsVal() << endl;

39: cout << "varThree: " << varThree.GetItsVal() << endl;

40:

41: return 0;

42: }

OUTPUT:

varOne: 2

varTwo: 4

varThree: 6

ANALYSIS: operator+ is declared on line 15 and defined on lines 28-31. Compare these with the declaration and definition of the Add() function in the previous listing; they are nearly identical. The syntax of their use, however, is quite different. It is more natural to say this:

varThree = varOne + varTwo;

than to say:

varThree = varOne.Add(varTwo);

Not a big change, but enough to make the program easier to use and understand.

NOTE: The techniques used for overloading operator++ can be applied to the other unary operators, such as operator-.

Operator Overloading: Binary Operators

Binary operators are created like unary operators, except that they do take a parameter. The parameter is a constant reference to an object of the same type.

Example 1

Counter Counter::operator+ (const Counter & rhs);

Example 2

Counter Counter::operator-(const Counter & rhs);

Issues in Operator Overloading

Overloaded operators can be member functions, as described in this unit, or non-member functions. The latter will be described in unit 14, "Special Classes and Functions," when we discuss friend functions.

The only operators that must be class members are the assignment (=), subscript([]), function call (()), and indirection (->) operators.

operator[] will be discussed tomorrow, when arrays are covered. Overloading operator-> will be discussed in Unit 14, when smart pointers are discussed.

Limitations on Operator Overloading

Operators on built-in types (such as int) cannot be overloaded. The precedence order cannot be changed, and the arity of the operator, that is, whether it is unary or binary, cannot be changed. You cannot make up new operators, so you cannot declare ** to be the "power of" operator.

New Term: Arity refers to how many terms are used in the operator. Some C++ operators are unary and use only one term (myValue++). Some operators are binary and use two terms (a+b). Only one operator is ternary and uses three terms. The ? operator is often called the ternary operator, as it is the only ternary operator in C++ (a > b ? x : y).

What to Overload

Operator overloading is one of the aspects of C++ most overused and abused by new programmers. It is tempting to create new and interesting uses for some of the more obscure operators, but these invariably lead to code that is confusing and difficult to read.

Of course, making the + operator subtract and the * operator add can be fun, but no professional programmer would do that. The greater danger lies in the well-intentioned but idiosyncratic use of an operator—using + to mean concatenate a series of letters, or / to mean split a string. There is good reason to consider these uses, but there is even better reason to proceed with caution. Remember, the goal of overloading operators is to increase usability and understanding.

DO use operator overloading when it will clarify the program. DON’T create counter-intuitive operators. DO return an object of the class from overloaded operators.

Back to Index