Overloading
extern void print(int); \fbox{print}
extern void print(float);
Generic class -- templates
template< class T > class list { ... } \fbox{ list<T> }
list<int>* alist;
Polymorphism by inheritance
class shape { ... }; \fbox{ shape }
class circle : public shape { ... }
shape* s = new circle;
slide: Polymorphic type declarations
In slide [1-polymorphism] some examples are given of
declarations involving polymorphic types.
The function print is separately defined for int and float.
Also, a generic list class is defined by means by employing
templates.
The list may be used for any kind of objects, for example integers.
Finally, a shape class is defined from which a circle class
is derived.
An instance of the circle may be referred to by using a shape
pointer, because the type shape encompasses circle objects.
Inheritance and virtual functions
The power of inheritance in C++ comes from virtual
functions and dynamic binding.
Dynamic binding realizes the polymorphism inherent
in the static type structure of the inheritance
hierarchy in a dynamic way.
Dynamic binding is illustrated
by the example shown in slide [7-dispatching].
Virtual functions -- dispatching
class A { \fbox{A}
public:
virtual void operator()() {
cout << "A";
}
};
class B : public A { \fbox{B}
public:
virtual void operator()() {
cout << "B";
}
};
// A* a = new B(); (*a)();
// produces: B
slide: Virtual functions -- dispatching
The class A defines a virtual member function
(that results in printing A) which is redefined
by a similar function in class B (which results
in printing B).
As an example of using the classes defined above,
look at the following program fragment:
A* a = new B(); (*a)();
In case the function would not have been defined as virtual,
the outcome of applying it to (a pointer to) a B object
would have been A, instead of B.
Virtual functions that are redefined in derived classes
may still access the original version defined in the base
class, as illustrated in slide [7-scoping].
Scoping -- explicit
class B : public A { \fbox{}
public:
virtual void operator()() {
cout << "B";
cout << "B";
A::operator()();
}
};
// A* a = new B(); a->A::operator()(); (*a)();
// produces: ABBA
slide: Virtual functions -- scoping
Scoping may be used within a member function of the
class as well as by a client (when invoking a member
function) as illustrated below.
A* a = new B(); a->A::operator()(); (*a)();
The outcome of this statement is ABBA.
Such a scoping mechanism is certainly not unique
to C++, although the notation for it is.
In Smalltalk, the expression super may be used
to access methods defined in the ancestor class,
and in Eiffel one must use a combination of
redefining and renaming to achieve this.
As a remark, I prefer the use of
operator()() when any other method name would
be arbitrary.
The attractiveness of operator()() is
that it is used as a function application
operator, as in (*a)().