OOP Etgar 2008 – Recitation 71 Object Oriented Programming Etgar 2008 Recitation 7
OOP Etgar 2008 – Recitation 72 Polymorphic Inheritance
OOP Etgar 2008 – Recitation 73 The Motivation Inheritance alone does not give us much strength except from moving the common code into base class. We would want the behavior to be dependent on the exact object’s type. Both OperaSingers and OrientalSingers are Singers, and they sing, but they do it differently.
OOP Etgar 2008 – Recitation 74 Static and Dynamic Binding We would like a way to “say” that a derived may provide own implementation for base’s method. This is called polymorphism – the behavior exhibited is dependent on the actual object type. This is done using dynamic binding – the compiler defers the decision which function to execute until runtime. The decision depends on the exact type of the object. With static binding the decision is made at compile-time.
OOP Etgar 2008 – Recitation 75 Virtual Keyword virtual on a method specifies that a derived class may provide its own implementation for that method (override). If the derived doesn’t want to override a virtual method, it doesn’t provide an implementation, and the implementation is inherited from base. A virtual method is dynamically bound, while non- virtual – statically.
OOP Etgar 2008 – Recitation 76 Example class Shape { public: virtual void draw() { cout << "I'm a shape"; } }; class Circle : public Shape { public void draw() { cout << "I'm a circle"; } };
OOP Etgar 2008 – Recitation 77 When Polymorphism Applies Polymorphic behavior requires two conditions: –Methods called must be virtual. –Objects must be manipulated through references or pointers. When manipulating an object directly, the compiler knows the exact type, so polymorphism is not used.
OOP Etgar 2008 – Recitation 78 Example void drw_ref(Shape& s) {s.draw();}// Polymorphic void drw_ptr(Shape* s) {s->draw();}// Polymorphic void drw_direct(Shape s) {s.draw();}// Statically bound int main() { Shape s; Circle c; drw_ref(s); drw_ptr(s); drw_direct(s); // Prints "I'm a shape" drw_ref(c); drw_ptr(c);// Prints "I'm a circle" drw_direct(c);// Prints "I'm a shape" }
OOP Etgar 2008 – Recitation 79 Slicing When a function’s parameter is a base object passed by value, the object passed to it is copied using base copy constructor. void func(Shape s); // Shape's copy ctor applies This ctor knows nothing about subclasses. Thus, only the base part of the object is copied This is called slicing and can be a source of errors.
OOP Etgar 2008 – Recitation 710 Overloading vs. Overriding Overloading means differentiating functions by their names and parameters. Overriding means providing own implementation for an inherited virtual method. Mixing the two is a bad idea – overriding an overloaded base method will hide all other versions (even if declared virtual ).
OOP Etgar 2008 – Recitation 711 Virtual and Scope Operator If the scope resolution operator :: is used, the virtual mechanism is ignored: void Circle::draw() { Shape::draw();// Static binding cout << "and a circle"; } c.draw(); // Prints "I'm a shape and a circle."
OOP Etgar 2008 – Recitation 712 Virtual Notes Constructors can’t be virtual. Calls to class’s virtual methods in its constructor and destructor are statically bound (but should be avoided). Default arguments are statically bound, even for virtual methods. virtual and static are mutually exclusive.
OOP Etgar 2008 – Recitation 713 Virtual Recommendations operator= shouldn’t be virtual. Never redefine inherited non- virtual methods. Overloaded functions shouldn’t be virtual. If the class is intended to be a base class, the destructor should be virtual. Compiler-generated destructor is not virtual, unless it’s for a class that inherits from a base with virtual destructor.
OOP Etgar 2008 – Recitation 714 Abstract Base Classes
OOP Etgar 2008 – Recitation 715 Interfaces While exploring the idea of polymorphism we discover that sometimes there is no meaningful implementation for the base class. There is no sensible Shape implementation and no sense creating Shape objects. The Shape is an interface – it specifies what behavior all its subclasses exhibit, but can’t provide a “default” implementation.
OOP Etgar 2008 – Recitation 716 ABC An interface in C++ can be specified by abstract base class (ABC). To make a class an ABC, make one or more of its methods a pure virtual function. A virtual function is “made pure” by the initializer =0.
OOP Etgar 2008 – Recitation 717 Example class Shape { public: virtual void draw() = 0;// Pure virtual virtual void rotate(int) = 0;// Pure virtual virtual move(int);// Non-pure }; int main() { Shape s;// Error Circle c;// Ok }
OOP Etgar 2008 – Recitation 718 What Does It Mean? An abstract class can be used only as a base for other classes (interface) – no objects of that class can be created. Derived classes provide implementations for pure virtual functions. A pure virtual function that is not defined in a derived remains pure virtual, and such derived class is also an abstract base.
OOP Etgar 2008 – Recitation 719 ABC Notes An ABC typically doesn’t need a constructor (but does need a virtual destructor). Pure virtual function can have an implementation in the ABC, and it can be called using scope resolution operator ::.