Operator Overloading and Templates
Chapter 13
Learning Outcomes
After completing this lecture and the related lab, students will be able to:
Explain the purpose and limitations of operator overloading, including which operators can be overloaded, restrictions on precedence/associativity, and why it is useful for user-defined types.
Differentiate between member and nonmember (
friend
) operator overloads.Implement common binary operators, assignment (
=
), stream insertion/extraction (<<
,>>
), and array indexing ([]
).Implement unary operators (pre/post increment and decrement) and explain how return types differ between mutable and const contexts.
Utilize the
this
pointer within member functions.
Lecture Video
Why Operator Overloading Is Needed
Consider the following statements:
ClockType local{8, 23, 34};
ClockType yourTime{4, 23, 30};
Which version of the C++ statements below would you prefer?
local.print();
local.incrementSeconds();
if (local.equal(yourTime))
// ...
cout << local;
local++;
if (local == yourTime)
// ...
Assignment and member selection are the only built-in operations on classes.
- Other operators cannot be applied directly to class objects.
Operator overloading extends the definition of an operator to work with a user-defined data type.
- C++ allows you to extend the definitions of most of the operators to work with classes.
Notes
Most existing C++ operators can be overloaded to manipulate class objects.
New operators cannot be created.
An operator function is a function that overloads an operator.
- Use reserved word
operator
followed by the operator as the function name.
- Use reserved word
Syntax for Operator Functions
Syntax of an operator function heading:
returnType operator symbol(formal parameter list)
It is a value-returning function.
operator
is a reserved word.
To overload an operator for a class:
Include the operator function declaration in the class definition.
Write the definition of the operator function.
Friend Functions of Classes
A friend function (of a class) is a nonmember function of the class that has access to all the members of the class.
Use the reserved word
friend
in the function prototype in the class definition.Friendship is always given by the class.
cppclass IllusFriend { friend void two(/*parameters*/); // ... };
Definition of a Friend Function
friend
does not appear in the heading of the function’s definition.When writing the
friend
function’s definition.The name of the class and the scope resolution operator are not used.
void two(/*parameters*/) { // ... }
Operator Functions as Member and Nonmember Functions
To overload
()
,[]
,->
, or=
for a class, the function must be a member of the class.Suppose
op
is overloaded foropOverClass
:If the leftmost operand of
op
is an object of a different type, the overloading function must be a nonmember (friend) of the class.If the overloading function for
op
is a member ofopOverClass
, then when applyingop
on objects of typeopOverClass
, the leftmost operand must be of typeopOverClass
.
Binary Operators
Overloading Binary Operators
If
#
represents a binary operator (e.g.,+
or==
) that is to be overloaded forrectangleType
.It can be overloaded as either a member function of the class or as a friend function.
Binary Operator Overloads as Methods
Function prototype (included in the class definition):
returnType operator#(const Type&) const;
Function definition:
cppreturnType operator#(const Type& otherObject) const { // algorithm to perform the operation return value; }
Binary Operator Overloads as Nonmember Functions
Function prototype (included in class definition):
friend returnType operator#(const Type&, const Type&) const;
Function definition:
returnType operator#(const Type& leftObject, const Type& rightObject) const { // algorithm to perform the operation return value; }
Overloading the Stream Insertion (<<
) and Extraction (>>
) Operators
Consider the expression:
cout << myRectangle;
- Leftmost operand is an
std::ostream
object, not arectangleType
object.
- Leftmost operand is an
Thus, the operator function that overloads
<<
forrectangleType
must be a nonmember function of the class.- The same applies to the function that overloads
>>
.
- The same applies to the function that overloads
Overloading the Stream Insertion Operator (<<
)
Function prototype:
cppfriend std::ostream& operator<<( std::ostream&, const Type&);
Function definition:
cppstd::ostream& operator<<(std::ostream& out, const Type& cObject) { // local declaration, if any // Output the members of cObject. // out << ... return out; // return the stream object. }
Overloading the Stream Extraction Operator (>>
)
Function prototype:
cppfriend std::istream& operator>>( std::istream&, Type&);
Function definition:
cppstd::istream& operator>>(std::istream& in, Type& cObject) { // local declaration, if any // Read the members of cObject. // in >> ... return in; // return the stream object. }
Overloading the Assignment Operator (=
)
Function prototype:const Type& operator=(const Type&);
Function definition:
const Type& operator=(const Type& rightObject)
{
// local declaration, if any
// Avoid self-assignment
if (this != &rightObject)
{
// Copy rightObject into this object
}
return *this; // return the object assigned
}
Classes with Pointer Members (Revisited)
Recall that the assignment operator copies member variables from one object to another of the same type.
- Does not work well with pointer member variables.
Classes with pointer member variables must:
Explicitly overload the assignment operator.
Include the copy constructor.
Include the destructor.
Member vs. Nonmember Operator Overloading
Some operators must be overloaded as member functions and some as nonmember (
friend
) functions.Binary arithmetic operators can be overloaded either way.
cppType operator+(const Type&);
or
cppfriend Type operator+(const Type&, const Type&);
Member Function for Operator Overload:
As a member function, the operation has direct access to data members of one of the objects.
Need to pass only one object as a parameter.
Non-Member Function for Operator Overload:
Both operands are included as parameters when nonmember functions that define binary operators.
The code may be somewhat clearer this way.
Overloading the Array Index Operator []
Declaring the
[]
operator as a class member for nonconstant arrays:Type& operator[](unsigned int index);
Declaring the
[]
operator as a class member for constant arrays:const Type& operator[](unsigned int index) const;
int array[5] { 1, 2, 3, 4, 5 };
const int ARRAY[5] { 1, 2, 3, 4, 5 };
std::cout << array[2];
std::cout << ARRAY[2]; // Const operator[]
array[2] = 10; // Non-const operator[]
// ARRAY[2] = 10; // Error
Unary Operators
To overload a unary operator for a class:
If the operator function is a member of the class, it has no parameters.
If the operator function is a nonmember (i.e., a
friend
function), it has one parameter.
Pre-Increment (++
) and Pre-Decrement (--
)
The general syntax to overload the pre-increment operator ++
as a member function.
Type operator++()
{
// Increment the value of the object by 1
return *this; //return the new value
}
Post-Increment (++
) and Post-Decrement (--
)
The general syntax to overload the post-increment operator ++
as a member function.
Type operator++(int)
{
const auto TEMP = *this; // copy old value
// Increment the value of the object by 1
return TEMP; // the copy of the old value
}
Post-Increment (++
) and Post-Decrement (--
) The general syntax to overload the post-increment operator ++
as a nonmember function.
Function prototype:
cppfriend Type operator++(Type&, int);
Function definition:
cppType operator++(Type& incObj, int) { const auto TEMP = incObj; // copy old // Increment the value of the object by 1 return TEMP; // the copy of the old value }
Some Restrictions
Cannot change the precedence of an operator.
Associativity cannot be changed.
Default parameters cannot be used.
Cannot change number of parameters.
Cannot create new operators.
Cannot overload:
.
.*
::
?:
sizeof
Operators on built-in types cannot be redefined.
Can overload for user-defined objects or for a combination of user-defined and built-in objects.
Quick Review
Overloaded operator – an operator that has different meanings with different data types.
Operator function – a function that overloads an operator.
Operator functions are value-returning.
Operator overloading provides the same concise notation for user-defined data types as for built-in data types.
Only existing operators can be overloaded.
The
this
pointer refers to the object.