You are on page 1of 14

Lecture overview

• Operator overloading
– Syntax
– Overloadable operators
– Unary operators
– Unusual operators
– Operators you can’t overload
– Overloading new and delete operators
Operator overloading
• Operator is just like any other function, except that the
arguments for this function don’t appear inside
parentheses, but instead they surround or are next to
special characters like +, -, *, /, &, etc.

• The compiler determines which function to call


depending on the type of the operands.

• In C++, it is possible to define new operators that work


with classes.

• This definition is just like an ordinary function definition


except that the name of the function consists of the
keyword operator followed by the operator.
Syntax
//: C12:OperatorOverloadingSyntax.cpp
#include <iostream>
using namespace std;
This is a small class that shows the
class Integer { syntax for operator overloading
int i;
public: The operator ‘+’ is overloaded here
Integer(int ii) : i(ii) {}
const Integer
operator+(const Integer& rv) const {
cout << "operator+" << endl;
return Integer(i + rv.i);
} The operator ‘+=’ is overloaded here
Integer&
operator+=(const Integer& rv) {
cout << "operator+=" << endl;
i += rv.i;
return *this; this means a pointer to the object
} for which the function was called
};
Syntax

• The two overloaded operators are defined as inline


member functions that announce when they are called.
• The single argument is what appears on the right-hand
side of the operator for binary operators.
• Unary operators don’t have arguments when defined as
member functions.
• The member function is called for the object on the left-
hand side of the operator.
• For non-conditional operators, you’ll almost always want
to return an object or a reference of the same type you
are operating on. This way, complicated expressions can
be built up:
kk += ii + jj;
Syntax

int main() {
cout << "built-in types:" << endl;
int i = 1, j = 2, k = 3;
k += i + j;
cout << "user-defined types:" << endl;
Integer ii(1), jj(2), kk(3);
kk += ii + jj;
} ///:~
This main function creates 3 objects (ii, jj, kk)
of the new class Integer and then uses them
with overloaded operators ‘+’ and ‘+=‘.
Overloadable operators

• Although you can overload almost all the operators


available in C, the use of operator overloading is fairly
restrictive.
– You cannot define operators that currently have no meaning in
C++ (such as **).
– You cannot change the evaluation precedence of operators.
– You cannot change the number of arguments required by an
operator.
Unary operators

• The following examples show the syntax to overload


some unary operators.

• For examples of all unary operators, see the


recommended textbook, p.489.
//: C12:OverloadingUnaryOperators.cpp
#include <iostream>
using namespace std;

// Non-member functions:
class Integer { Global function definitions:
long i; const Integer operator-(const Integer&
Integer* This() { return this; } a) {
public: cout << "-Integer\n";
return Integer(-a.i);
Integer(long ll = 0) : i(ll) {}
}
// No side effects takes const& const Integer operator~(const Integer&
argument: a) {
friend const Integer cout << "~Integer\n";
operator-(const Integer& a); return Integer(~a.i);
friend const Integer }
operator~(const Integer& a);
// Side effects have non-const& Unary – and ~ operators are declared here
argument:
// Prefix:
friend const Integer&
operator++(Integer& a); You have to declare different operators for
// Postfix: prefix and postfix increment and decrement.
friend const Integer When the compiler sees ++a, it generates a
operator++(Integer& a, int);call to operator++(a). When it sees a++,
}; it generates a call to operator++(a, int).
See operator definitions on the next slide.
Prefix and postfix increment
operators
// Prefix; return incremented value
const Integer& operator++(Integer& a) {
cout << "++Integer\n";
a.i++;
return a;
}
// Postfix; return the value before increment:
const Integer operator++(Integer& a, int) {
cout << "Integer++\n";
Integer before(a.i);
a.i++;
return before;
}
Unusual operators
• The subscript, operator[], must be a member function and it requires a single
argument.
• Because operator[] implies that the object it’s being called for acts like an array,
you will often return a reference from this operator, so it can be used on the left
hand-side of an equal sign.
• This operator is commonly overloaded, there will be examples in the following
lectures.
• Operators new and delete will be overloaded in the following lectures as well.

Operators you can’t overload


• operator->

• operator* (dereference)

• You can’t make up operators which don’t exist in the standard operator set.
For example: operator-+
Overloading new and delete
• When you create a new-expression, two things occur:
– First, storage is allocated using the operator new();
– The constructor is called
• In a delete-expression, the destructor is called, then storage is
deallocated using the operator delete().
• You cannot control the constructor and destructor calls.
• You can change the storage allocation functions operator
new() and operator delete().
• In special situations, standard new and delete might not serve your
needs. The common reason to change them is allocator efficiency.
• C++ allows you to overload new and delete to implement your
own storage allocation scheme, so you can handle problems like
this.
Overloading new and delete

• Overloading new and delete is like overloading any


other operator.

• However, you have a choice of overloading the global


allocator or using a different allocator for a particular
class.
Example:
//: C13:GlobalOperatorNew.cpp
// Overload global new/delete
#include <cstdio>
#include <cstdlib> Continued on the next slide…
using namespace std;

void* operator new(size_t sz)


{
printf("operator new: %d Bytes\n", sz);
void* m = malloc(sz);
if(!m) puts("out of memory");
return m;
}
void operator delete(void* m)
{
puts("operator delete");
free(m);
}
Example (continued):
class S {
int i[100];
public:
S() { puts("S::S()"); }
~S() { puts("S::~S()"); }
};

int main() {
puts("creating & destroying an int");
int* p = new int(47);
delete p;
puts("creating & destroying an s");
S* s = new S;
delete s;
puts("creating & destroying S[3]");
S* sa = new S[3];
delete []sa;
} ///:~

You might also like