C++ — Polymorphism
Virtual functions
#include <iostream>
using namespace std;
class Shape {
public:
virtual double area() const { return 0; }
virtual string type() const { return "Shape"; }
virtual ~Shape() = default;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override { return 3.14159 * radius * radius; }
string type() const override { return "Circle"; }
};
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override { return width * height; }
string type() const override { return "Rectangle"; }
};
void printArea(const Shape &s) {
cout << s.type() << " area: " << s.area() << endl;
}
int main() {
Circle c(5);
Rectangle r(4, 6);
printArea(c); // Circle area: 78.5398
printArea(r); // Rectangle area: 24
// Polymorphism with pointers
Shape *shapes[] = {&c, &r};
for (const auto *s : shapes) {
printArea(*s);
}
return 0;
}
Pure virtual functions and abstract classes
#include <iostream>
using namespace std;
class Animal {
public:
virtual void speak() const = 0; // Pure virtual
virtual ~Animal() = default;
};
// class Animal a; // Error: can't instantiate abstract class
class Dog : public Animal {
public:
void speak() const override { cout << "Woof!" << endl; }
};
class Cat : public Animal {
public:
void speak() const override { cout << "Meow!" << endl; }
};
int main() {
// Animal a; // Error
Dog dog;
Cat cat;
dog.speak();
cat.speak();
// Array of base class pointers
Animal *zoo[] = {&dog, &cat};
for (const auto *a : zoo) {
a->speak();
}
return 0;
}
Virtual destructor
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Base constructed" << endl; }
virtual ~Base() { cout << "Base destroyed" << endl; }
};
class Derived : public Base {
private:
int *data;
public:
Derived() : data(new int[100]) {
cout << "Derived constructed" << endl;
}
~Derived() override {
delete[] data;
cout << "Derived destroyed" << endl;
}
};
int main() {
Base *ptr = new Derived();
delete ptr; // Without virtual destructor: only Base destructor called
return 0;
}
Abstract class with interface
#include <iostream>
#include <string>
using namespace std;
class Serializable {
public:
virtual string serialize() const = 0;
virtual ~Serializable() = default;
};
class Loggable {
public:
virtual string toLogString() const = 0;
virtual ~Loggable() = default;
};
class User : public Serializable, public Loggable {
private:
string name;
int age;
public:
User(string n, int a) : name(n), age(a) {}
string serialize() const override {
return "{\"name\":\"" + name + "\",\"age\":" + to_string(age) + "}";
}
string toLogString() const override {
return "[USER] " + name + " (age " + to_string(age) + ")";
}
};
int main() {
User u("Alice", 30);
cout << u.serialize() << endl;
cout << u.toLogString() << endl;
return 0;
}
Dynamic casting
#include <iostream>
using namespace std;
class Animal {
public:
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void fetch() { cout << "Fetching!" << endl; }
};
class Cat : public Animal {
public:
void purr() { cout << "Purring!" << endl; }
};
int main() {
Animal *a = new Dog();
// dynamic_cast checks at runtime
Dog *dog = dynamic_cast<Dog *>(a);
if (dog) {
dog->fetch(); // OK
}
Cat *cat = dynamic_cast<Cat *>(a);
if (cat) {
cat->purr(); // Never reached
} else {
cout << "Not a cat" << endl;
}
delete a;
return 0;
}
Typeid
#include <iostream>
#include <typeinfo>
using namespace std;
class Base {
public:
virtual ~Base() = default;
};
class Derived : public Base {};
int main() {
Base *ptr = new Derived();
cout << "Type: " << typeid(*ptr).name() << endl;
cout << "Is Derived? " << (typeid(*ptr) == typeid(Derived)) << endl;
delete ptr;
return 0;
}
CRTP (Curiously Recurring Template Pattern)
#include <iostream>
using namespace std;
template <typename Derived>
class Counter {
static int count;
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { return count; }
};
template <typename Derived>
int Counter<Derived>::count = 0;
class Dog : public Counter<Dog> {};
class Cat : public Counter<Cat> {};
int main() {
Dog d1, d2;
Cat c1;
cout << "Dogs: " << Dog::getCount() << endl; // 2
cout << "Cats: " << Cat::getCount() << endl; // 1
return 0;
}
Mini Practice
Write C++ code that:
- Creates an abstract
Vehicleclass with pure virtualstart()andstop() - Implements
CarandMotorcyclederived classes - Uses
dynamic_castto check the actual type at runtime - Demonstrates virtual destructor importance
Up Next
In the next lesson, you'll learn about Templates — generic programming in C++.
Related Topics
Frequently Asked Questions about Polymorphism
What is Polymorphism in C++?
Polymorphism is a fundamental concept in C++. This lesson explains it step by step with clear examples, making it easy for beginners to understand.
How do I learn Polymorphism?
Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Polymorphism.
Why is Polymorphism important in C++?
Polymorphism is essential for C++ development. Understanding this concept will help you write better code and solve real-world problems more effectively.