Professional Documents
Culture Documents
Lec11 (Topic 6 Polymorphism)
Lec11 (Topic 6 Polymorphism)
Polymorphism
What is Polymorphism?
-Polymorphism is allowing objects of different types to respond
differently to the same method call.
int main() {
Animal a;
a.move(); // cout "Moving"
...
}
Animal::move() is called.
No problem
int main() {
Animal* a = new Animal;
a->move(); // cout "Moving"
...
}
Static Polymorphism
Call the move() method from a Bird object or a pointer to an Bird object.
int main() {
Bird b;
b.move(); // cout "Moving"
...
}
Animal::move() is called.
No problem
int main() {
Bird* b = new Bird;
b->move(); // cout "Moving"
...
}
Static Polymorphism
Call the move() method for a Bird object using a pointer
to an Animal
int main() {
Bird* b = new Bird;
Animal* a = b; // Upcasting
a->move(); // cout "Moving"
...
}
Animal::move() is called.
No problem
int main() {
Bird b;
Animal* a = &b; // Upcasting
a->move(); // cout "Moving"
...
}
Static Polymorphism
• Static binding always occurs when subclass does not override
superclass method. It generally does not introduce problem.
+ move()
Static Polymorphism
Call the move() method from an Animal object or a pointer to an Animal
object
int main() {
Animal a;
a.move(); // cout "Moving"
...
}
Animal::move() is called.
No problem
int main() {
Animal* a = new Animal;
a->move(); // cout "Moving"
...
}
Static Polymorphism
Call the move() method from a Bird object or a pointer to a Bird
object
int main() {
Bird b
b.move(); // cout "Flying"
...
}
Bird::move() is called. No
problem
int main() {
Bird* b = new Bird;
b->move(); // cout "Flying"
...
}
Static Polymorphism: Problem
Call the move() method for a Bird object using a pointer to an
Animal object (upcasting)
int main() {
Bird* b = new Bird;
Animal* a = b; // Upcasting
a->move(); // cout "Moving"
...
Animal::move() is still called but
}
Bird::move() is more
appropriate/precise/accurate in the
context. This happens when
int main() { upcasting
Bird b;
Animal* a = &b; // Upcasting
a->move(); // cout "Moving"
...
}
Static Polymorphism: Problem
Call the move() method for a Bird object using a reference to an
Animal object (upcasting)
int main() {
Bird b;
Animal& a = b; // Upcasting via reference
a.move(); // cout "Moving"
...
}
Static Polymorphism: Problem
class Animal {
public:
virtual void move() {
cout << "Moving"; }
};
int main() {
Bird* b = new Bird;
Animal* a = b; // Upcasting
a->move(); // cout "Flying"
...
}
Bird::move() is called now, which is
more appropriate/precise/accurate
in context
int main() {
Bird b;
Animal* a = &b; // Upcasting
a->move(); // cout "Flying"
...
}
Dynamic Polymorphism
Upcasting via reference. After making the move() method virtual.
int main() {
Bird b;
Animal& a = b; // Upcasting via reference
a.move(); // cout "Flying"
...
}
Dynamic Polymorphism: Benefit
The primary benefit of dynamic polymorphism is it enables to write
codes that work for all objects from the 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"; }
};
Dynamic Polymorphism: Benefit
We can write a single callMove() function that call the right version of
move() method for all objects in the animal inheritance hierarchy.
void callMove (Animal & a) {
a.move();
}
int main() {
Animal a;
Bird b;
Fish f;
Mammal m; Output:
callMove (a);
callMove (b); Moving
callMove (f); Flying
callMove (m); Swimming
return 0; Walking
}
Dynamic Polymorphism: Benefit
We can also write a loop that calls the right version of move()
method for all objects in the animal inheritance hierarchy.
int main() {
// Array of different animals
Animal* a[4] = {new Animal,
new Bird,
new Fish,
new Mammal};
for (int i = 0 ; i < 4; i++) Output:
a[i]->move();
return 0; Moving
} Flying
Swimming
Walking
Virtual Destructor
• Superclass destructor should always be virtual for delete operator
to call the destructors correctly
• Otherwise, delete operator will call only superclass destructor, not
the subclass destructor.
• This will cause only the base part of the object to be destroyed.
Virtual Destructor
// Solution
class Super {
public:
virtual ~Super() {
cout << "Super destroyed\n"; }
};
class Sub : public Super {
public:
virtual ~Sub() {
cout << "Sub destroyed\n"; }
};
Output:
int main() {
Sub destroyed
// upcasting
Super destroyed
Super* p = new Sub;
delete p; // invoke destructor
return 0;
}
Abstract Base Class
• An abstract class is a class that cannot be instantiated.