C++ Dynamic Binding
C++ Dynamic Binding
Language
Motivation
Dynamic Binding
Outline
Motivation
Dynamic vs. Static Binding
Shape Example
Calling Mechanisms
Downcasting
Run-Time Type Identication
Summary
Motivation (cont'd)
Motivation (cont'd)
{ Information hiding and data abstraction provide compile-time and link-time place-holders
Dynamic binding is less powerful than pointersto-functions, but more comprehensible and
less error-prone
{ i.e., since the compiler performs type checking
at compile-time
;
Derived d;
bp = &d;
bp->vf (); // invokes Derived::vf()
:::
In C++, this requires that both the general and specialized methods are virtual
functions
4
Motivation (cont'd)
{ Not all design decisions need to be known during the initial stages of system development
the system
:::
{ e.g.,
template <class T>
class Checked Vector : public Vector<T>
;
Checked Vector<int> cv (20);
Vector<int> *vp = &cv;
int elem = (*vp)[0]; // calls operator[] (int)
{ A question arises here as to which version of
operator[] is called?
f :::g
Caveats:
Inheritance review
{ Dynamic Binding
;
Note, virtual functions must be class methods, i.e.,
they cannot be:
g
{ Class data
{ Static methods
Virtual functions:
:::
{ e.g.,
void foo (Base *bp)
g
11
Base b;
Base *bp = &b;
bp->vf1 (); // prints "hello"
Derived 1 d;
bp = &d;
bp->vf1 (); // prints "world"
foo (&b); // prints "hello"
foo (&d); // prints "world"
12
Shape Example
:::
The virtual mechanism is set up by the constructor(s), which may stack several levels
deep
:::
{ e.g.,
void foo (Base *bp)
bp->vf1 ();
// Actual call
// (*bp->vptr[1])(bp);
14
13
{ e.g.,
typedef struct Shape Shape;
struct Shape
enum
CIRCLE, SQUARE,
TRIANGLE, RECTANGLE
/* Extensions go here . */
type ;
:::
union
struct Circle /* . */ c ;
struct Square /* . */ s ;
struct Triangle /* . */ t ;
struct Rectangle /* . */ r ;
:::
:::
:::
:::
u;
;
void rotate shape (Shape *sp, double degrees)
switch (sp->type )
case CIRCLE: return;
case SQUARE: // Don't forget to break!
//
g
:::
g
g
15
Therefore, modications will occur in portions of the code that switch on the type
tag
:::
2. Transparent extensibility
4. Architectural simplicity
18
17
Rectangle
Triangle
Circle
Color
1
Point
Shape
fg
1
1
Note, the \OOD challenge" is to map arbitrarily complex system architectures into
inheritance hierarchies
19
private:
g
Point center ;
Color color ;
20
:::
:::
22
21
i.e., they are simply there to tie the inheritance hierarchy together by reserving a slot
in the virtual table
:::
23
{ Furthermore, you will have to provide a denition (i.e., write the code for a method) for the
pure virtual destructor in the base class
24
{ e.g.,
class Circle : public Shape
public:
Circle (Point &p, double rad);
virtual void draw (Screen &);
virtual void rotate (double degrees)
//
private:
double radius ;
;
class Rectangle : public Shape
public:
Rectangle (Point &p, double l, double w);
virtual void rotate (double degrees);
virtual void draw (Screen &);
//
private:
double length , width ;
fg
:::
sp->rotate (degrees);
// (*sp->vptr[1]) (sp, degrees);
:::
26
25
Rotate
vtable (Rectangle)
Draw
vptr
vptr
Circle
Rectangle
Rotate
Draw
class
Rather than with function rotate shape
{ This makes it possible to add new types (derived from base class Shape) without breaking
existing code
i.e., most extensions/changes occur in only
one place
This code will continue to work regardless of what derived class of Shape that sp
actually points to, e.g.,
Circle c;
Rectangle r;
:::
27
28
sp->rotate (degrees);
Square s;
Circle c;
Rectangle r;
Note, the C or Ada approach prevents extensibility if the provider of Square does
not have access to the source code of
function rotate shape!
{ i.e., only the header les and object code is
required to allow extensibility in C++
30
29
vec[i]->rotate (angle);
else
/* FALLTHROUGH */;
vec[i]->rotate (angle)
tion call
is a virtual func-
case RECTANGLE:
//
break;
:::
{ i.e.,
31
32
vtable (Circle)
Shape *shapes[] =
new Circle (/* . */),
new Square (/* . */)
;
int size = sizeof shapes / sizeof *shapes;
rotate all (shapes, size, 98.6);
vtable (Square)
:::
Rotate
Draw
Rotate
Draw
:::
vptr
Circle
Square
shapes
vptr
33
34
Calling Mechanisms
Shape Example (cont'd)
The appropriate choice of techniques often depends on whether the class interface
is stable or not
{ Adding a new subclass is easy via inheritance,
but dicult using union/switch (since code is
35
36
Static Binding
38
37
vptr
{ Main advantages
f1
f2
vtable
0
obj 1
{ Main disadvantages
Less ecient
vptr
vptr
obj 2
obj 3
e.g.,
class Foo
public:
virtual int f1 (void);
virtual int f2 (void);
int f3 (void);
private:
f
// data
;
Foo obj 1, obj 2, obj 3;
:::
39
40
Downcasting
:::
3. Taking an object out of a heterogeneous collection of objects and restoring its original type
{ Also hard to do, unless the only access is via
the interface of the base class
42
41
Downcasting (cont'd)
Contravariance
Downcasting (cont'd)
dp
bp
Base b;
Derived d;
Base *bp = &d; // OK, a Derived is a Base
Derived *dp = &b;// Error, a Base is not
// necessarily a Derived
43
44
:::
Downcasting (cont'd)
Downcasting (cont'd)
Contravariance (cont'd)
{ Since a Derived object always contains a Base
part certain operations are well dened:
bp = &d;
bp->i = 10;
bp->foo (); // calls Derived::foo ();
{ However, since base objects do not contain the
data portions of any of their derived classes,
other operations are not dened
:::
dp = (Derived *) &b;
dp->j = 20; // big trouble!
{ Note, C++ permits contravariance if the programmer explicitly provides a downcast, e.g.,
dp = (Derived *) &b; // unchecked cast
46
Downcasting (cont'd)
RTTI is a technique that allows applications to use the C++ run-time system to
query the type of an object at run-time
48
For a dynamic cast to succeed, the \actual type" of ob1 would have to either be
a Derived object or some subclass of Derived
e.g.,
void clone (Base &ob1)
try
f
/*
To throw an exception
e.g., in the case of reference casts
:::
*/
Derived &ob2 =
:::
/*
:::
*/
49
50
:::
e.g.,
51
Summary
53