C++ Crash Kurs Polymorphism Dr. Dennis Pfisterer Institut für Telematik, Universität zu Lübeck http://www.itm.uni-luebeck.de/people/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 2
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 3
C++ Inheritance: Dynamic Binding Compiler decides at run-time which method is invoked Depending on the type pointed-at object Key-word virtual Example 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 object s type is BMW Example: introvirtual.cpp 4
C++ Inheritance: Dynamic Binding Compiler adds type information to the classes data structures to determine the object s type at runtime 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 Base Base TypeInfo Base* TypeInfo Derived* Base* 5
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) Exception Derived class may return Derived* instead of Base* 6
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 Behavior In constructors, virtual methods of the current class are invoked Same applies to destructors 7
C++ Inheritance: Why is virtual an option? Why is virtual an option if it triggers the correct behavior? C++ philosophy: If you don t use, you don t 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 Don t 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 8
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() } } 9
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? Vehicle Car Lorry Bike BMW VW 10
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 Syntax virtual method-signature = 0; Examples class A virtual void f() = 0; }; class B virtual void f(const int x&) const = 0; }; 11
C++ Inheritance: pure virtual methods Interface and implementation class Lamp public: virtual void on() = 0; virtual void off() = 0; }; Usage class LightBulb : public Lamp public: void on() } void off() } private: }; void switch_on(lamp& l) l.on(); } LightBulb lb; switch_on(lb); //Polymorphism LightBulb::on() Example: purevirtual.cpp 12
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 Advantages Code (new behaviors) can be added without requiring changes to other classes Easy implementation of interfaces Disadvantages Dynamic binding introduces run-time overhead 13
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) 14
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 Example Vehicle *v = new BMW BMW* bmw = dynamic_cast<bmw*> v; VW* vw = dynamic_cast<vw*> v; if( bmw!= NULL ) } else if( vw!= NULL ) } 15