04. Operator Overloading
Overview
- Operator overloading is a specific case of polymorphism in which some or all of operators like +, =, or == have different implementations depending on the types of their arguments.
- Operator overloading is useful because it allows the developer to program using notation closer to the users domain and allows user defined types to look like types built into the language.
Criticism
- Operator overloading has often been criticized because it allows programmers to give operators completely different semantics depending on the types of their operands.
- For example: the operator new can be overloaded to perform a delete operation.
Restrictions
- You cannot change the precedence of an operator.
- An overloaded operator cannot have default arguments
- You must declare the overloaded =, [], (), and -> operators as nonstatic member functions to ensure that they receive lvalues as their first operands.
- The operators new, delete, new[], and delete[] do not follow the general rules described in this section.
- All operators except the = operator are inherited.
All Operator Except
- Member of: .
- Binding: .*
- Scope: ::
- Ternary: ?:
- Preprocessor: #
- Sizeof: sizeof
Syntax
- C++ introduces a keyword to the language called ‘operator’. The operator is really a simple disguise for a function. For example, given the prototypes:
- Person& plus(person& p);
- Person& operator + (person& p);
- Can be implemented the same, but called differently:
- Person cperson = aperson.plus(bperson);
- Person cperson = aperson + bperson;
Versions
- To make an operator like ‘+’ be fully functional in all contexts for your class objects, it needs to support the following syntax:
- + object; // unary version
- objectA + objectB; // binary version
- objectA + integer; // binary version with intrinsic
- integer + objectA; // intrinsic with binary version
Unary Versions
void Employee::operator +()
{
salary += amount;
}
- In this case, the ‘amount’ variable is an internal class variable. To use this operator:
Employee bob;
+ bob;
- Note: using the syntax: bob+; has no compiler context, so this context would generate a compiler error.
Binary Version
void Employee::operator + ( Employee& right )
{
salary += right.salary;
}
- To use this operator:
Employee bob, jack;
bob + jack;
- Note that bob is on the left hand side of the + and jack is on the right. Consequently, the ‘this’ pointer of the + operation belongs to bob (as bob is on the left of the + sign and jack is on the right.
Binary version with Intrinsic
void Employee::operator + ( float right )
{
salary += right;
}
- To use this operator:
Employee bob;
bob + 123.45;
- Note bob is on the left hand side of the + operation and contains the ‘this’ pointer. The float is on the right hand side of the + operation.
Intrinsic with Binary Version
Employee& operator + ( float L, Employee& R )
{
R.salary += L;
}
- To use this operator:
Employee bob;
123.45 + bob;
- Note the float is on the left hand side of the + operation and the Employee is on the right.
Complications
- Here’s where it gets complicated: Each ‘member’ function (and operator), has the ‘this’ pointer passed as the first argument. Consequently, if the operator is programmed like this:
Employee& operator + ( float left, Employee& right )
{
right.salary += left;
}
- What we really have is this:
Employee& operator + ( Employee* this, float L, Employee& R )
- This is a ternary operator, because the operator is being passed three operands. Ternary operators are not supported in C++ and the operator + is not a ternary operator.
Friend Operator
- To get around this limitation, declare the prototype to this operator as a friend in the header file:
friend void operator + (float,student&);
- This eliminates the ‘this’ pointer from being passed as the first parameter to this operator.
Chaining
- To support ‘chaining’, you can return values from operators:
Employee& operator + (Employee&);
- The function could be implemented as:
Employee& Employee::operator + ( Employee& right )
{
salary += right.salary;
return *this;
}
Using Chaining
- To chain the operations:
Employee alice, bob, cathy;
Employee don = alice + bob + cathy;
- The + operations are handled by operator + and the assignment is handled by operator =.
Conversion Operators
- The “casting” or “boxing” operators can also be overloaded. This syntax support converting one type to another type:
student::operator char*()
{
return name;
}
- Converts a student to a char*:
char* pname = (char*)astudent;
Summary
- In C++ you can add new operations for your class objects. For example, you can ‘add’ two employees together.
- What does it mean to ‘add’ two employees together? Answer: Anything the programmer wants, including complete non-sense.
- Operators should be added to your class objects when it makes your code easier to understand, rather than harder to understand.