Title: Ch 7. Operator Overloading
1Ch 7. Operator Overloading
2Introduction
- Almost all operators in C can be overloaded
with new meanings. - Operators may not look like functions but can
hide function invocations. - You cannot overload the meaning of operators if
all arguments are primitive data types, nor can
you change the precedence or associativity of
operators.
3Figure 7.1 Overloadable Operators in C
- - /
- !
- -- ltlt gtgt ,
- lt lt ! gt gt
- - /
- ltlt gtgt
- () -gt new delete
4Overloaded Functions or Methods
- Operators can be defined either as functions or
as member functions. - How to decide which option is preferable
- An ordinary function is normally not permitted
access to the private portions of the class,
whereas a member function is allowed such access. - Implicit conversions will be performed for both
right and left arguments if the operator is
defined in functional form, but only for the
right argument if the operator is defined as a
member function.
5Figure 7.2 Comparison Defined as an Ordinary
Function
- class box public box (int v) value(v)
int value -
- // define meaning of comparison for boxes
- bool operator lt (box left, box right)
return left.value lt right.value -
6Figure 7.3 Comparison Defined as a Member Function
- class box public box (int v) value(v)
- // define meaning of comparison for boxes
- bool operator lt (box right) return value
lt right.value - private int value
-
7Simple Binary Operators
- const rational operator
- (const rational left, const rational
right) - // return sum of two rational
numbers rational result ( left.numerator()
right.denominator() right.numerator()
left.denominator(), left.denominator()
right.denominator())return result -
8Simple Binary Operators
- Unary operations are either defined as a
no-argument ordinary function or as a no-argument
member function. - Always return a constant value, unless you want
the result to be a target for an assignment. - rational a(2,3), b(7,8)(a b) b
- // error constant result cannot be reassigned
9The Comparison Operators
- bool operator lt (const rational left, const
rational right) - // less than comparison of two rational
numbersreturn left.numerator()
right.denominator() lt right.numerator()
left.denominator() -
- // define greater than in terms of less than
- template ltclass Tgt
- bool operator gt (T left, T right) return
right lt left
10The Increment and Decrement Operators
- If the increment operator is overloaded, you
should define both the prefix and postfix forms. - Whenever you have a choice, always invoke the
prefix form of the increment operator as it is
usually simpler.
11- class box public box (int v) value(v)
- // prefix versions, aBox int operator ()
value return value int operator -- ()
value-- return value - int operator (int) // postfix versions
aBox - int result value // step 1, save old
value value // step 2, update value return
result // step 3, return original int
operator -- (int) int result
value value-- return result private
int value
12- class box public ...const box operator
() value return this -
- box mybox(3)
- mybox // error - cannot increment constant
value - mybox 7 // error - cannot assign to constant
value - mybox 7 // error - cannot assign to constant
value
13- Avoid expressions whose meanings are not
completely clear. - int i 5int x i i
- // ambiguous result
14The Shift Operators
- The shift operators are overloaded in exactly the
same fashion as the binary arithmetic operators. - cout ltlt "m " ltlt m ltlt " n " ltlt n ltlt " average " ltlt
(nm)/2.0 ltlt '\n'
15- ostream operator ltlt
- (ostream out, const rational value)
- // print representation of rational number on
an output streamout ltlt value.numerator() ltlt '/'
ltlt value.denominator()return out -
- Avoid the right shift of signed integer values.
16The Assignment Operator
- The assignment, comma, and address-of operators
will be constructors will be constructed
automatically if the programmer does not specify
an alternative. -
- class box public box () value 0
box (int i) value i int
value box a(7) box b b a
17- Always redefine the assignment operator in
classes that include a pointer value. - const box operator (box left, const box
right) left.value right.value return
left -
- const box operator (box left, int right)
left.value right return left -
- box c
- c a
- b 2 (a 3)
18- Always check for self-assignment.
-
- a a // make certain this works
- const string stringoperator (const string
right) - if (this right) // check for self
assignment return right ... -
19- Despite the use of the assignment symbol,
constructors do not use the assignment operator. - box d c // uses copy constructor
- If addition and assignment are both overloaded,
then should be overloaded as well.
20- class bigbox public box public bigbox (int
i, double d) box(i), dvalue(d) void
operator (bigbox right) value
right.value dvalue right.dvalue protecte
d double dvalue -
- box a(3)
- bigbox b(3, 4.0)
- a b // legal, but sliced, box assignment,
- b a // not legal, argument must be a bigbox
21The Compound Assignment Operators
- Whenever possible, define one operator in terms
of another. - AnObject operator (const AnObject left, const
AnObject right) AnObject clone(left) // copy
the left argumentclone right // combine with
rightreturn clone // return updated value -
- const AnObject operator (AnObject left,
const AnObject right) AnObject sum left
rightleft sumreturn left
22The Subscript Operator
- Subscript operator is often defined for classes
that represent a container abstraction. - class safeArray public safeArray (int s)
size s values new intsize int
operator (unsigned int i) assert(i lt
size) return valuesi private unsign
ed int size int values
23- The real vector data type does not check
subscript ranges. - safeArray v(10) v2 7 v3 v2 12
- When returning a referenc, make sure that the
value will continue to exist after the function
exists.
24The Parenthesis Operator
- Function Object an object that can be used as
though it were a function. - class LargerThan public //
constructor LargerThan (int v) val v
// the function call operator bool
operator () (int test) return test gt val
private int val
25- LargerThan tester(12)
- int i ...
- if (tester(i)) // true if i is larger than 12
- A temporary object can be created by simply
naming the class and any arguments to the
constructor. - listltintgtiterator found find_if
(aList.begin(), aList.end(), LargerThan(12))
26The Address-of Operator
- Rate to use, but when it yields a value of type
void produces a class of objects that cannot have
their address computed, it is useful. - class box public box () i 7
private int i -
- box a
- box b // b is a pointer to a box
- b a // b now points to a
27The Logical Connectives
- Short-circuit evaluation means that in some
situations only the left argument is evaluated,
and the right argument is not even examined. - There is no way to overload the logical operators
and preserve the short-circuit evaluation.
28The Comma Operator
- The for statements in Java and C use the same
syntax and achieve a similar result but use
different mechanisms. - int i, j for (i 0, j 1 xi ! 0
i) if (xi xj) j
29- Mistakenly taping a comma instead of a period can
be a very subtle programming error. - x 7,12
- class box template ltclass Tgt const T
operator , (T right) return right
30- An overloaded comma operator can never have the
same short-circuit semantics as the original. - class box public box (int v) val(v)
int value () return val int operator
, (box right) - return right.value() private int
val
31The Arrow Operator
- Overloading arrow operator is useful in creating
objects that have a pointer-like behavior. - The arrow operator can be defined only as a
member function, and the return type must either
be a pointer to a class type or an object for
which the member access arrow is itself defined. - A smart pointer is an object that can be used in
the manner of a pointer.
32Example of Arrow Operator
- class countPointer public countPointer(Window
w) - count 0 win w Window operator-gt()
- count return win private Window
win int count -
- Window x new Window(...) // create the
underlying value - countPointer p(x) // create a counting pointer
value - p-gtsetSize(300, 400) // invoke method in class
window
33Conversion Operators
- Conversions from user types are defined by
conversion operators conversions to user types
are defined by using constructors. -
- operator double (const rational val) return
val.numerator() / (double) val.denominator() - rational r (2, 3) double dd 3.14
double(r) // cast converts fraction to double
34Example of Conversion Operators
- class rational ... operator double ()
const return numerator() / (double)
denominator() ...
35Memory management Operators
- It is possible to overload the memory management
operators new and delete, obtaining even more
control over these tasks than is provided by the
default implementations.
36Disallowing Operators
- An operator declared as private can be used only
within a class definition. - class box public box (int v) val(v)
int value () return val private void
operator (box right) box aBox (2) //
create a new boxbox bBox (3) // and
anotheraBox bBox // error -- assignment is
private
37Implicit Functions and Invocations
- Implicit function definitions and implicit
function invocations are invoked without the
programmer directly requesting it.
38Implicitly Created Operations
- The default construct, copy constructor,
destructor, assignment operator, address
operator, and comma operator will all be given
implicit meanings unless overridden by the
programmer. - class emptyBox public box private box
aField
39- class emptyBox public box public //
constructors emptyBox () box() , aField()
emptyBox (const emptyBox right)
box(right), aField(right.aField) - emptyBox() // destructor // implicit
deletion of aField // implicit call on parent
class destructor const emptyBox operator
(const emptyBox right) // operators aField
right.aField boxoperator (right) return
this emptyBox operator () return
this template ltclass Tgt const T operator ,
(const T right) return right private box
aField
40- Implicit Constructors
- If no constructor are specified, an implicit
default constructor constructor will be created. - First, invoke the default constructor for the
parent class if the current class was formed by
using inheritance. - The function will recursively apply default
initialization rules for every data field. - An implicit copy constructor is created if no
other copy constructor is specified, even if
other constructors have been defined.
41- Implicit Destructors
- First, invoke destructors for every data field
and then invoke the destructor for the parent
class. - Fields are destroyed in the opposite order listed
in the class body. - An implicit destructors is never considered
virtual.
42- Implicit Assignment Operator
- Created implicitly, takes as an argument a value
of the same type as the class and recursively
assigns each data field from the corresponding
fields in the argument object. - If there is parent class, the assignment operator
for the parent class is then invoked.
43- Implicit Address and Comma
- The implicit address simply returns a reference
to the current object. - The implicit comma operator simply returns a
reference to the argument object.
44Implicit Function Invocations
- Implicit function invocation can greatly increase
a programs execution time. - A copy constructor always invoked to pass a
by-value object.
45- class box public box () value 0 box
(int i) value i box (box a) value
a.value box() // destructor void
operator (box right) value
right.value operator int () return value
private int value -
- box operator (box left, box right) return
box(((int) left) (int) right)
46- int foo (box abox)
- box bboxbbox abox 1return bbox
-
- int main()
- box mybox(3)mybox 4mybox foo (mybox
1)return 0
47- box mybox(3) // integer constructor mybox
4 // integer constructor to create
temporary // assignment of temporary to
variable // destructor on temporary mybox
foo (mybox 1) // start of statement //
integer constructor to create temporary //
binary addition of boxes box operator (box
left, box right) return box(((int) left)
(int) right) // inside addition operator //
conversion of left box to integer // conversion
of right box to integer // integer constructor
for temporary // return from addition
operator mybox foo (mybox 1) //
continuation of statement box bbox // inside
function foo // default constructor to create
variable
48- bbox abox 1 // start execution //
integer constructor to create temporary for
constant // binary addition operator for
boxes box operator (box left, box
right) return box(((int) left) (int) right)
// inside addition operator // conversion of
left box to integer // conversion of right box
to integer // integer constructor for
temporary bbox abox 1 // continue
execution // assignment for boxes //
destructor for temporary // conversion from box
to integer // destructor for local variable
bbox // return from function // destructor
for temporary argument mybox foo (mybox 1)
// continuation of statement // integer
constructor converting result to box //
assignment operation // destructor of temporary
value // destructor of variable mybox
49- class string public // constructors string
(char c) ... string (const string s)
... string (int i) ... -
- string aString 'a'
- class string public // constructors string
(char c) ... string (const string s)
... explicit string (int i) ...