Motivation
Copyright c 1997-2006 Vanderbilt University 1
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 2
Copyright c 1997-2006 Vanderbilt University 3
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Dynamic binding facilitates more flexible and extensible software Inheritance review
architectures, e.g.,
– A pointer to a derived class can always be used as a pointer to a
– Not all design decisions need to be known during the initial stages base class that was inherited publicly
of system development Caveats:
i.e., they may be postponed until run-time The inverse is not necessarily valid or safe
– Complete source code is not required to extend the system Private base classes have different semantics...
i.e., only headers & object code – e.g.,
template <typename T>
This aids both flexibility & extensibility class Checked_Vector : public Vector<T> { ... };
Checked_Vector<int> cv (20);
– Flexibility = ‘easily recombine existing components into new Vector<int> *vp = &cv;
configurations’ int elem = (*vp)[0]; // calls operator[] (int)
– Extensibility = “easily add new components” – A question arises here as to which version of operator[] is called?
Copyright c 1997-2006 Vanderbilt University 4
Copyright c 1997-2006 Vanderbilt University 5
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Dynamic vs. Static Binding (cont’d) Dynamic vs. Static Binding (cont’d)
The answer depends on the type of binding used... When to chose use different bindings
1. Static Binding: the compiler uses the type of the pointer to – Static Binding
perform the binding at compile time. Therefore, Use when you are sure that any subsequent derived classes
Vector::operator[](vp, 0) will be called will not want to override this operation dynamically (just
2. Dynamic Binding: the decision is made at run-time based upon redefine/hide)
the type of the actual object. Checked Vector::operator[] Use mostly for reuse or to form “concrete data types”
will be called in this case as (*vp->vptr[1])(vp, 0) – Dynamic Binding
Use when the derived classes may be able to provide a different
Quick quiz: how must class Vector be changed to switch from static
(e.g., more functional, more efficient) implementation that
to dynamic binding?
should be selected at run-time
Used to build dynamic type hierarchies & to form “abstract data
types”
Copyright c 1997-2006 Vanderbilt University 6
Copyright c 1997-2006 Vanderbilt University 7
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Efficiency vs. flexibility are the primary tradeoffs between static & In C++, dynamic binding is signaled by explicitly adding the keyword
dynamic binding virtual in a method declaration, e.g.,
struct Base {
Static binding is generally more efficient since virtual int vf1 (void) { cout << "hello\n"; }
1. It has less time & space overhead int f1 (void);
};
2. It also enables method inlining
Dynamic binding is more flexible since it enables developers to
– Note, virtual methods must be class methods, i.e., they cannot be:
extend the behavior of a system transparently Ordinary “stand-alone” functions
class data
– However, dynamically bound objects are difficult to store in Static methods
shared memory
Other languages (e.g., Eiffel) make dynamic binding the default...
– This is more flexible, but may be less efficient
Copyright c 1997-2006 Vanderbilt University 8
Copyright c 1997-2006 Vanderbilt University 9
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 10
Copyright c 1997-2006 Vanderbilt University 11
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 12
Copyright c 1997-2006 Vanderbilt University 13
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 14
Copyright c 1997-2006 Vanderbilt University 15
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Data structures are “passive” An object-oriented solution uses inheritance & dynamic binding to
derive specific shapes (e.g., Circle, Square, Rectangle, &
– i.e., functions do most of processing work on different kinds of
Triangle) from a general Abstract Base class (ABC) called Shape
Shapes by explicitly accessing the appropriate fields in the object
– This lack of information hiding affects maintainability This approach facilities a number of software quality factors:
Solution wastes space by making worst-case assumptions wrt 1. Reuse
structs & unions 2. Transparent extensibility
3. Delaying decisions until run-time
Must have source code to extend the system in a portable,
4. Architectural simplicity
maintainable manner
Copyright c 1997-2006 Vanderbilt University 16
Copyright c 1997-2006 Vanderbilt University 17
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 18
Copyright c 1997-2006 Vanderbilt University 19
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Note, certain methods only make sense on subclasses of class ABCs support the notion of a general concept (e.g., Shape) of
Shape which only more concrete object variants (e.g., Circle & Square)
are actually used
– e.g., Shape::rotate() & Shape::draw()
ABCs are only used as a base class for subsequent derivations
The Shape class is therefore defined as an abstract base class
– Therefore, it is illegal to create objects of ABCs
– Essentially defines only the class interface
– However, it is legal to declare pointers or references to such
– Derived (i.e., concrete) classes may provide multiple, different
objects...
implementations
– ABCs force definitions in subsequent derived classes for
undefined methods
In C++, an ABC is created by defining a class with at least one “pure
virtual method”
Copyright c 1997-2006 Vanderbilt University 20
Copyright c 1997-2006 Vanderbilt University 21
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Pure virtual methods must be methods The only effect of declaring a pure virtual destructor is to cause the
class being defined to be an ABC
They are defined in the base class of the inheritance hierarchy, &
are often never intended to be invoked directly Destructors are not inherited, therefore:
– i.e., they are simply there to tie the inheritance hierarchy together – A pure virtual destructor in a base class will not force derived
by reserving a slot in the virtual table... classes to be ABCs
– Nor will any derived class be forced to declare a destructor
Therefore, C++ allows users to specify ‘pure virtual methods’
Moreover, you will have to provide a definition (i.e., write the code for
– Using the pure virtual specifier = 0 indicates methods that are
a method) for the pure virtual destructor in the base class
not meant to be defined in that class
– Note, pure virtual methods are automatically inherited... – Otherwise you will get run-time errors!
Copyright c 1997-2006 Vanderbilt University 22
Copyright c 1997-2006 Vanderbilt University 23
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Vanderbilt University
It’s easier to add new types without breaking existing code since
subclass sp actually points to, e.g.,
vtable (Rectangle)
Rectangle r;
Copyright c 1997-2006
Rectangle::rotate (degree);
Douglas C. Schmidt
Circle c;
}
vtable (Circle)
Circle
vptr
/* .... */
0
};
Copyright c 1997-2006 Vanderbilt University 27
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 28
Copyright c 1997-2006 Vanderbilt University 29
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Comparing the Two Approaches (cont’d) Comparing the Two Approaches (cont’d)
/* C solution */
void rotate_shape (Shape *sp, double degree) { Example function that rotates size shapes by angle degrees:
switch (sp->type_) { void rotate_all (Shape *vec[], int size, double angle)
case CIRCLE: return; {
case SQUARE: for (int i = 0; i < size; i++)
if (degree % 90 == 0) vec[i]->rotate (angle);
return; }
else
/* FALLTHROUGH */; vec[i]->rotate (angle) is a virtual method call
case RECTANGLE:
// ... – It is resolved at run-time according to the actual type of object
break; pointed to by vec[i]
} – i.e.,
} vec[i]->rotate (angle) becomes
(*vec[i]->vptr[1]) (vec[i], angle);
Copyright c 1997-2006 Vanderbilt University 30
Copyright c 1997-2006 Vanderbilt University 31
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Comparing the Two Approaches (cont’d) Comparing the Two Approaches (cont’d)
vtable (Circle) vtable (Square)
Copyright c 1997-2006 Vanderbilt University 32
Copyright c 1997-2006 Vanderbilt University 33
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Note that both the inheritance/dynamic binding & union/switch Given a pointer to a class object (e.g., Foo *ptr) how is the
statement approaches provide mechanisms for handling the design method call ptr->f (arg) resolved?
& implementation of variants
There are three basic approaches:
The appropriate choice of techniques often depends on whether the
1. Static Binding
class interface is stable or not
2. Virtual Method Tables
– Adding a new subclass is easy via inheritance, but difficult using 3. Method Dispatch Tables
union/switch (since code is spread out everywhere)
C++ & Java use both static binding & virtual method tables, whereas
– On the other hand, adding a new method to an inheritance
Smalltalk & Objective C use method dispatch tables
hierarchy is difficult, but relatively easier using union/switch (since
the code for the method is localized) Note, type checking is orthogonal to binding time...
Copyright c 1997-2006 Vanderbilt University 34
Copyright c 1997-2006 Vanderbilt University 35
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Method f’s address is determined at compile/link time Method f() is converted into an index into a table of pointers to
functions (i.e., the “virtual method table”) that permit run-time
Provides for strong type checking, completely checkable/resolvable
resolution of the calling address
at compile time
– The *ptr object keeps track of its type via a hidden pointer
Main advantage: the most efficient scheme
(vptr) to its associated virtual method table (vtable)
– e.g., it permits inline method expansion
Virtual methods provide an exact specification of the type signature
Main disadvantage: the least flexible scheme
– The user is guaranteed that only operations specified in class
declarations will be accepted by the compiler
Copyright c 1997-2006 Vanderbilt University 36 Copyright c 1997-2006
Vanderbilt University 37
OO Progra
Douglas C. Schmidt OO Programming with C++
Vanderbilt University
Main advantages
obj 3
vptr
1. More flexible than static binding
f1
1
2. There only a constant amount of overhead (compared with
method dispatching)
vtable
0
not in the object!
Main disadvantages
int f3 (void);
– Less efficient, e.g., often not possible to inline the virtual method
obj 2
vptr
// data ...
Copyright c 1997-2006
calls...
class Foo {
Douglas C. Schmidt
obj 1
private:
vptr
public:
e.g.,
};
Copyright c 1997-2006 Vanderbilt University 38
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
– i.e., new methods can be added or deleted on-the-fly Downcasting is useful for
– & allows users to invoke any method for any object 1. Cloning an object
Main disadvantage: generally inefficient & not always type-secure – e.g., required for “deep copies”
2. Restoring an object from disk
– May require searching multiple tables at run-time – This is hard to do transparently...
– Some form of caching is often used 3. ‘Taking an object out of a heterogeneous collection of objects &
– Performing run-time type checking along with run-time method restoring its original type‘
invocation further decreases run-time efficiency – Also hard to do, unless the only access is via the interface of
– Type errors may not manifest themselves until run-time the base class
Copyright c 1997-2006 Vanderbilt University 40
Copyright c 1997-2006 Vanderbilt University 41
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
struct Base {
int i_;
virtual int foo (void) { return i_; }
}; b d
i i
struct Derived : public Base {
int j_;
virtual int foo (void) { return j_; }
? j
};
void foo (void) {
Base b;
Derived d;
Base *bp = &d; // "OK", a Derived is a Base
Derived *dp = &b;// Error, a Base is not necessarily a Derived Problem: what happens if dp->j_ is referenced or set?
}
Copyright c 1997-2006 Vanderbilt University 42
Copyright c 1997-2006 Vanderbilt University 43
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 44
Copyright c 1997-2006 Vanderbilt University 45
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 46
Copyright c 1997-2006 Vanderbilt University 47
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 48
Copyright c 1997-2006 Vanderbilt University 49
Douglas C. Schmidt OO Programming with C++ Douglas C. Schmidt OO Programming with C++
Copyright c 1997-2006 Vanderbilt University 50
Copyright c 1997-2006 Vanderbilt University 51