You are on page 1of 15

Institute of Telematics | University Lbeck

C++ Program 7. Polymorphism

Dr.-Ing. Dennis Pfisterer

C++ Polymorphism
Major abstractions of C++
Data abstraction (using classes) Class relationships (using inheritance)

However, often upcasting does not offer the desired behavior Example
class Car { public: void start() { cout << "Car::start()" << endl; } }; class BMW : public Car { public: void start() { cout << "BMW::start()" << endl; } }; int main(int argc, char** argv) { Car *car = new BMW; car->start(); //Calls Car::start(), not BMW::start() delete car; }

Example: intro.cpp

C++ Polymorphism Standard behavior

The type of the pointer, not the type of the object determines the method to invoke

Desired behavior
The type of the object, not the type of the pointer should determine the method to invoke

Concept called polymorphism

Even if it looks the same (same pointer type), it may behave differently (different types of objects) Key concept for the understanding of object oriented programming

C++ Inheritance: Dynamic Binding

Compiler decides at run-time which method is invoked
Depending on the type pointed-at object Key-word virtual

class Car { virtual void start () { ... } // Car::start }; class BMW : public Car { virtual void start () { ... } //Redefinition: BMW::start redefines Car::start }; Car *car; BMW *bmw; car = new Car; car->f(x); //Invokes Car::f bmw = new BMW; b->f(x); //Invokes BMW::f car = new BMW; //UPCAST !!! car->f(x); //Invokes BMW::f since the objects type is BMW

Example: introvirtual.cpp

C++ Inheritance: Dynamic Binding

Compiler adds type information to the classes data structures to determine the objects type at run-time
Keyword virtual tells the compiler to not to perform static binding (only for virtual methods)

Compilers implement this behind the scenes by adding vtables

They list address offsets of virtual functions for this object Method invocations require additional level of indirection (performance)

Derived Memory address








C++ Inheritance: Name hiding Recall

Redefinition of non-virtual identifiers

Virtual methods behave differently

Not called redefinition, but overriding No different return types are allowed (to guarantee a common polymorphic interface)

Derived class may return Derived* instead of Base*

C++ Inheritance: Behavior in constructors Problem

Derived classes have not been initialized while the in the constructor of the base class runs As a result, virtual functions can not be invoked as they might invoke non-initialized code

In constructors, virtual methods of the current class are invoked Same applies to destructors

C++ Inheritance: Why is virtual an option?

Why is virtual an option if it triggers the correct behavior?
C++ philosophy: If you dont use, you dont pay for it

Virtual function calls need slightly more performance

Additional level of indirection through vtable Inhibits several other performance optimizations possible with static binding

Dont be worried about efficiency in the first place

When designing classes, use polymorphism (virtual) extensively Optimization is possible later if the class concept is designed well

Example: exhaustiveexample.cpp

C++ Inheritance: Virtual destructors

Objects are deleted from memory using pointers
In conjunction with polymorphism, which destructor is called? Base* b = new Derived; b->do_something(); delete b; Same behavior as with non-virtual methods: Type of the pointer determines the function (here: destructor) invoked

Classes using polymorphism (virtual) must implement virtual destructors

class A { public: virtual ~A() { } virtual f() { } }

C++ Inheritance: Designing interfaces

Often, base classes only provide an interface and no functionality
What is start() supposed to do for Vehicle or Car ? Vehicle and Car provide the interface to the outside BMW and VW provide real functionality


How to avoid implementing of such interface methods?





C++ Inheritance: pure virtual methods

C++ provides the concept of abstract classes
Pure virtual methods have no implementation A class containing pure virtual methods can not be instantiated Abstract classes provide a common interface that sub-classes implement


virtual method-signature = 0;

class A { virtual void f() = 0; }; class B { virtual void f(const int x&) const = 0; };

C++ Inheritance: pure virtual methods

Interface and implementation
class Lamp { public: virtual void on() = 0; virtual void off() = 0; }; class LightBulb : public Lamp { public: void on() {} void off() {} private: };


void switch_on(Lamp& l) { l.on(); } LightBulb lb; switch_on(nl); //Polymorphism LightBulb::on()

Example: purevirtual.cpp

C++ Inheritance: Summary polymorphism Properties

The type of the object pointed-at is important, not the type of the pointer Only for functions declared to be virtual


Code (new behaviors) can be added without requiring changes to other classes Easy implementation of interfaces

Dynamic binding introduces run-time overhead

C++ Inheritance: Object slicing

Passing derived objects by reference or pointer is always safe
f(Base *b) { } or f(Base &b) { } Derived d; f(&d); or f (d);


OK, pointed-at object is still of type Derived

Passing derived objects by value leads to object slicing

f(Base b) { } Derived d; f(d);

b is a copy of d of type Base (which may not be what you wanted)

C++ Inheritance: Down-Casting

Sometimes its necessary to perform a safe down-cast
Type* t = dynamic_cast<Type*> variable; Returns NULL if the conversion was not possible Only applicable to pointers


Introduces some runtime overhead

Should not be used too often If used very often, there is a good chance of your design being flawed

Vehicle *v = new BMW BMW* bmw = dynamic_cast<BMW*> v; VW* vw = dynamic_cast<VW*> v; if( bmw != NULL ) { } else if( vw != NULL ) { }