Lecture04 polymorphism

632 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
632
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
34
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Lecture04 polymorphism

  1. 1. Lecture 4TCP1201 OOPDS 1
  2. 2. Learning ObjectivesTo understand static polymorphism and dynamicpolymorphismTo understand the problem of staticpolymorphismTo enable dynamic polymorphism via virtualfunctionTo understand the benefit of dynamicpolymorphismTo understand abstract classTo understand why virtual destructor is needed 2
  3. 3. What is Polymorphism?-Polymorphism is allowing objects of different typesto respond differently to the same method call.-Polymorphism occurs when there is functionoverriding. - In lecture 3, superclass Human has a speak method and is overridden by subclass Student. Invoking the speak method from Human has different result than Invoking the speak method from Student. 3
  4. 4. Different objects invoke different version of methods with the same name (speak())class Animal { public: void speak() { How does C++ knows cout << "Im an animaln"; which method to call? } Through function call}; bindingclass Bird : public Animal { public: void speak() { // overriding cout << "Im a birdn"; } Output:}; Im an animal Im a birdint main() { Animal* a = new Animal; a->speak(); // call Animal::speak() Bird* b = new Bird; b->speak(); // call Bird::speak() delete a; delete b; 4}
  5. 5. Function Call Binding• Connecting a function call to a function body is called binding• Function call binding is the process of determining what blockof function code is executed when a function call is made. class Animal { Memory public: void speak() { ... } }; Animal::speak() 0x7723 class Bird : public Animal { Definition public: void speak() { ... } }; Bird::speak() 0x77b4 int main() { Definition Animal* a = new Animal; a->speak(); Bird* b = new Bird; b->speak(); delete a; delete b; 5 }
  6. 6. Function Call BindingThere are 2 types of function call binding(polymorphism): Early/Static/Compile-timebinding/polymorphism: Binding is performedduring compile-time, and is decided by the compilerand linker based on the variable used to invoke themethod. Late/Dynamic/Runtime binding/polymorphism:Binding occurs at runtime, based on the type of theobject calling the method. 6
  7. 7. Static Polymorphism• It is the polymorphism that is implemented using static binding.• The compiler determines beforehand what method definition will be executed for a particular method call, by looking at the type of the variable invoking the method.• We have been using static polymorphism thus far without realizing it. 7
  8. 8. Static PolymorphismConsider the following Animal hierarchy, subclassBird overrides superclass Animals move()method.class Animal { Animal public: void move() { cout << "Moving"; } + move():void};class Bird : public Animal { public: void move() { cout << "Flying"; } Bird}; + move():void 8
  9. 9. Static PolymorphismCall the move() method from an Animal object, an Animalpointer/reference to an Animal object, a Bird object, or an Birdpointer/reference to a Bird object, got overriding but noupcasting => no problemint main() { Animal a1; a1.move(); // cout "Moving". Animal *a2 = new Animal; // Pointer. a2->move(); // cout "Moving". Animal& a3 = a1; // Reference. Animal::move() is called. a3.move(); // cout "Moving". No problem Bird b1; b1.move(); // cout "Flying". Bird *b2 = new Bird; // Pointer. b2->move(); // cout "Flying". Bird& b3 = b1; Bird::move() is called. No b3.move(); // cout "Flying". problem 9}
  10. 10. Static Polymorphism: ProblemCall the move() method from a Bird object using anAnimal pointer/reference, got overriding and gotupcasting => big problem.int main() { Bird* b1 = new Bird; Animal* a1 = b1; // Upcasting via pointer. a1->move(); // cout "Moving". Bird b2; a1 = &b2; // Upcasting via pointer. a1->move(); // cout "Moving". Animal& a2 = b2; // Upcasting via reference. a2.move(); // cout "Moving". delete b1;} Animal::move() is still called but Bird::move() is more appropriate/precise/accurate in the context. 10
  11. 11. Static Polymorphism: ProblemConsider the following inheritance hierarchy:class Animal { public: void move() { cout << "Moving"; }};class Bird : public Animal { public: void move() { cout << "Flying"; }};class Fish : public Animal { public: void move() { cout << "Swimming"; }};class Mammal : public Animal { public: void move() { cout << "Walking"; }}; 11
  12. 12. Static Polymorphism: Problem 1 To make a function callMove() to support every class in the animal inheritance hierarchy, we have to write/overload the callMove() function for every class.// 1 callMove() only.void callMove (Animal & a) Output: int main() {{ ... Animal a; Moving a.move(); Bird b;} Moving Fish f; Moving// 4 callMove() for Mammal m; Moving// 4 different classes. callMove (a);void callMove (Animal & a) callMove (b);{ ... a.move(); } callMove (f); Output:void callMove (Bird & b) callMove (m);{ ... b.move(); } } Movingvoid callMove (Fish & f) Flying{ ... f.move(); } Swimmingvoid callMove (Mammal & m) Walking 12{ ... m.move(); }
  13. 13. Static Polymorphism: Problem 1We can actually solve the problem in previous slides byusing template. However the downside is the templatefunction wont be limited to the Animal hierarchy anymore. // template callMove(). // Work but not limited to Animal hierarchy. template <typename T> void callMove (T & a) { ... a.move(); } 13
  14. 14. Static Polymorphism: Problem 2We cannot use one for loop to call the correct versionof move() method in an array/vector of objects fromAnimal hierarchy. Current output:int main() { Moving // Array of different animals. Moving Animal* a[4] = {new Animal, Moving new Bird, Moving new Fish, new Mammal}; Preferred output: for (int i = 0 ; i < 4; i++) a[i]->move(); Moving for (int i = 0 ; i < 4; i++) Flying delete a[i]; Swimming} Walking 14
  15. 15. Dynamic Polymorphism• The solution to the upcasting problem we just discussed is to enable dynamic polymorphism or dynamic binding via the use of virtual function.• Requirements for C++ dynamic polymorphism: • There must be an inheritance hierarchy. • The superclass must have a virtual method. • Subclass must override superclass virtual method. • A superclass pointer/reference to a subclass object (upcasting) is used to invoke the virtual method. 15
  16. 16. Virtual Function• In order to allow a method to be bound at run-time, it must be declared as virtual in the superclass.• By declaring a method as virtual in superclass, it is automatically virtual in all subclasses. class Animal { public: virtual void move() { // Enable dynamic binding. cout << "Moving"; } }; class Bird : public Animal { public: void move() { // Automatically virtual. cout << "Flying"; } }; 16
  17. 17. Virtual Function We can use the keyword virtual at subclass virtual function to remind ourselves that it is using dynamic binding. class Animal { public: virtual void move() { cout << "Moving"; } }; class Bird : public Animal { public: virtual void move() { // Optional, as reminder. cout << "Flying"; } }; 17
  18. 18. Dynamic PolymorphismAfter making the move() method virtual:int main() { Bird* b1 = new Bird; Animal* a1 = b1; // Upcasting via pointer. a1->move(); // cout "Flying". Bird b2; a1 = &b2; // Upcasting via pointer. a1->move(); // cout "Flying". Animal& a2 = b2; // Upcasting via reference. a2.move(); // cout "Flying". delete b1;} Bird::move() is called now, which is more appropriate/precise/accurate in the context. 18
  19. 19. Dynamic Polymorphism: BenefitThe primary benefit of dynamic polymorphism is itenables to write codes that work for all objects fromthe same inheritance hierarchy via upcasted pointer/ reference.Consider the following inheritance hierarchy:class Animal { public: virtual void move() { cout << "Moving"; }};class Bird : public Animal { public: virtual void move() { cout << "Flying"; }};class Fish : public Animal { public: virtual void move() { cout << "Swimming"; }};class Mammal : public Animal { public: virtual void move() { cout << "Walking"; }}; 19
  20. 20. Dynamic Polymorphism: BenefitWe can write a single callMove() function that callthe correct version of move() method for all objectsin the Animal hierarchy.void callMove (Animal & a) { ... a.move();} Output:int main() { Animal a; Moving Bird b; Flying Fish f; Swimming Mammal m; Walking callMove (a); callMove (b); callMove (f); callMove (m); 20}
  21. 21. Dynamic Polymorphism: BenefitWe can also write a loop to call the correct versionof move() method for all objects in the Animalhierarchy.int main() { // Array of different animals. Output: Animal* a[4] = {new Animal, new Bird, Moving new Fish, Flying new Mammal}; Swimming for (int i = 0 ; i < 4; i++) Walking a[i]->move(); for (int i = 0 ; i < 4; i++) delete a[i];} 21
  22. 22. Abstract Class An abstract class is a class that cannot be instantiated. A class that can be instantiated is called a concrete class. – All classes that we have learned so far are concrete classes. The reason to make a class abstract is, due to some requirements/constraints, we want to make it impossible to create instance(s) of the class. To be an abstract class: a class must have at least a pure virtual function. 22
  23. 23. Pure Virtual Function A pure virtual function is a method that is initialized to zero (0) in its declaration and no implementation is given in the class. Pure virtual function makes the class abstract and no instance of the class can be created.class Animal { // Abstract class. public: virtual void move() = 0; // Pure virtual function.};int main() { Animal a1; // ERROR: Animal is an abstract class. Animal* a2 = new Animal; // ERROR: same reason. ...} 23
  24. 24. Pure Virtual Function Subclass of an abstract class must override all of the superclass pure virtual functions in order to become a concrete class (instantiate-able).class Animal { // Abstract superclass. public: virtual void move() = 0; // Pure virtual function.};class Bird : public Animal { // Concrete subclass. public: virtual void move() { // Overriding pure virtual function. cout << "Flying"; }};int main() { Animal *a = new Bird; // Fine. create a Bird object. a->move(); // cout "Flying“.} 24
  25. 25. Pure Virtual Function Subclass that does not override superclass pure virtual function is an abstract class too. class Animal { // Abstract class. public: virtual greet() {} virtual void move() = 0; // Pure virtual function. }; class Bird : public Animal { // Abstract class. public: virtual void greet() { ... } }; class Eagle : public Bird { // Concrete class. public: virtual void greet() { ... } virtual void move() { ... } // Overriding. }; 25
  26. 26. Virtual Destructor Superclass destructor should always be virtual in order for the delete operator to call the destructors correctly for an subclass object that is created via upcasting. Otherwise, the delete operator will call only superclass destructor, not the subclass destructor. – This will cause only the base part of the object to be destroyed.// Problem int main() {class Super { Super* p = new Sub; // Upcasting. public: delete p; // Invoke destructor. ~Super() { // Non virtual. } cout << "Super destroyedn"; }};class Sub : public Super { Output: // Where is Subs destructor? public: Super destroyed ~Sub() { cout << "Sub destroyedn"; } 26};
  27. 27. Virtual Destructor// Solution  To ensure thatclass Super { subclass objects are public: destroyed properly, virtual ~Super() { make superclass cout << "Super destroyedn"; } destructor virtual.};class Sub : public Super { public: virtual ~Sub() { Output: cout << "Sub destroyedn"; } Sub destroyed}; Super destroyedint main() { Super* p = new Sub; // Upcasting. delete p; // Invoke destructor.} 27
  28. 28. Good Programming Practices Use inheritance to promote code reusability. Use virtual function to describe common behavior within a family of classes. Use pure virtual function to force subclasses to define the virtual function. Use a pointer/reference to an abstract base class to invoke virtual function, thus implementing dynamic polymorphism. 28

×