C++ allows overloading of function definitions, meaning two or more functions can have the same name as long as their parameter lists differ. [It is not enough for their return types to differ.]
Operator Overloading
Operator overloading is one of the key features of C++. Most common operators can be overloaded, and overloaded definitions are expected to be somewhat consistent with their usual functionality.
- You can define any typical operator (
+-*/<|&=[]etc) to have any meaning when operating on objects of your class - Allows very succinct code to be written, e.g.
mySet += otherSetto add one set to another for objects of aSetclass that you have defined - See the Wikipedia operator overloading page for a reference of all operators that can be overloaded, and also what the overloaded function prototypes are expected to be
- Define by writing a class member function named
operator$where$is the desired operator symbol(s) - e.g. methods namedoperator*,operator[],operator<< - For unary class member operators, the function prototype needs no parameters. The object to which the operator is applied is the implicit parameter (*this).
- For binary operators, prototype requires a parameter that is the right operand. Again, the left operand is expected to be a member of the class in which the operator is defined.
- The compiler "magically" wires use of the infix operator
$on your class to youroperator$method operator$etc are regular method names;myob.operator$(otherob)is legal (assuming the symbol chosen is allowed)
Rule of Three
If you have a non-trivial destructor,
you should also explicitly define a copy constructor and operator=. This is because a non-trivial destructor implies there is dynamic memory allocated for each object. The default copy constructor and operator= implementation will only do a shallow copy, but you likely need a deep copy instead.
Note that operator== is not part of the rule of three because a default version is not provided for your class types - you must always define it explicitly. However, if you have a non-trivial destructor, then probably your equality operator definition needs to be deep, similar to the assignment operator and copy constructor.
Overloading assignment operator
Example prototype for overloading assignment, = on a class named Bag - const Bag& Bag::operator=(const Bag & right). Note the lack of const at the end of the prototype - this operator is expected to change the value of the Bag that appears on the left of the operator in use.
- Overloading
=changes meaning of the default assignment operator - recall default=is same as for Cstructs, shallow copy of all fields -
conston return type above prevents(s1 = s2) = s3 - Overloading
+and=doesn't provide automatic overloading of+=, it must be done explicitly - Overloading can also be done in a friend function, see right column of the Wikipedia page - but overloading operators
() [] -> =must be with a class member function - Use reference return types to create l-values that can be assigned to
- eg:
int & Bag :: operator[] (int subscript) -
&in above meansBag[1] = 23;works; leave off the&and it won't work
- eg:
- Overload again for constant Bag objects
const int & Bag :: operator [] (int subscript) const
C++ string class operator overloading
- The
stringlibrary class includes lots of overloaded operator member functions - some overload operators include
== != < > <= >=
Explicit type conversions with classes
- Conversion constructor member functions convert from single parameter type to the class type
- Cast conversion operator can convert from class type to that specified
- If defined, will be invoked implicitly by compiler when conversion is needed
Rational :: operator double() const; // Rational to double precision floating point Fraction :: operator Rational() const; // Fraction class to Rational class
- Must be a non-static member function, not a friend
- Casting member functions have no return type specified, the value returned is the type being cast to, so no need to list it twice
Friend Functions
Friend functions enable us to give a [helper, non-class] function access to private members of a particular class. Friends violate the principle of data encapsulation - use as little as possible!!
- Declared with
friendkeyword in class definition (header file) - Defined outside the class (no use of ClassType:: scope operator)
- Has access to all members of class (private and public)
Overloading via friend functions
If the first argument (left operand) of a binary operator is not of a class type, you can’t overload with a member method. Instead, you can overload with a friend function.
Example for overloading << on a Rational class:
- Write a function with prototype
ostream & operator<<(ostream & os, const Rational & r) - This function will define an overloaded
<<binary operator where lhs is a stream object and rhs is aRationalobject - Need to declare
friend ostream& operator<<(ostream &, const Rational &);in class header - lets this (non-member) functionoperator<<have access to private fields - Note use of
ostream&return type; the updated stream should be returned allowing for chaining of other stream insertion operations </ul>