Polymorphism is a core concept in C++ and is categorized into two types:
- Static polymorphism: Functon addresses are bound early during compilation (static linking). Examples include function overloading and operator overloading, which reuse function names under this category.
- Dynamic polymorphism: Function addresses are bound late during runtime (dynamic linking). This is achieved using derived classes and virtual functions to implement runtime polymorphism.
A virtual function is declared in a base class using the virtual keyword. When a derived class redefines a virtual function from the base class, it instructs the compiler to avoid static linking for that function.
The goal is to select the appropriate function to call based on the actual type of the object at any point in the program. This mechanism is referred to as dynamic linking or late binding.
Virtual Function Syntax
virtual return_type function_name() {};
Example of Virtual Functions
#include <iostream>
class BaseEntity {
public:
virtual void display() {
std::cout << "BaseEntity display" << std::endl;
}
};
class DerivedA : public BaseEntity {
public:
void display() override {
std::cout << "DerivedA display" << std::endl;
}
};
class DerivedB : public BaseEntity {
public:
void display() override {
std::cout << "DerivedB display" << std::endl;
}
};
int main() {
BaseEntity* entityPtr;
DerivedA objA;
entityPtr = &objA;
entityPtr->display();
DerivedB objB;
entityPtr = &objB;
entityPtr->display();
return 0;
}
Output:
DerivedA display
DerivedB display
If the virtual keyword is omitted from the base class function, the output becomes:
BaseEntity display
BaseEntity display
Pure Virtual Funcsions
When a virtual function defined in a base class cannot have a meaningful implementation but needs to be redefined in derived classes, a pure virtual function is used.
Pure Virtual Function Syntax
virtual return_type function_name() = 0;
Example of Pure Virtual Functions
#include <iostream>
class AbstractBase {
public:
virtual void render() = 0;
};
class RendererA : public AbstractBase {
public:
void render() override {
std::cout << "RendererA output" << std::endl;
}
};
class RendererB : public AbstractBase {
public:
void render() override {
std::cout << "RendererB output" << std::endl;
}
};
int main() {
AbstractBase* renderer;
RendererA a;
renderer = &a;
renderer->render();
RendererB b;
renderer = &b;
renderer->render();
return 0;
}
Output:
RendererA output
RendererB output
Key Notes
- A class containing at least one pure virtual function is considered an abstract class.
- Abstract classes cannot be instantiated directly.
- Any derived class must implement all pure virtual functions from its parent class; otherwise, the derived class also becomes an abstract class.