Define polymorphic classes
suggest changeThe typical example is an abstract shape class, that can then be derived into squares, circles, and other concrete shapes.
The parent class:
Let’s start with the polymorphic class:
class Shape {
public:
virtual ~Shape() = default;
virtual double get_surface() const = 0;
virtual void describe_object() const { std::cout << "this is a shape" << std::endl; }
double get_doubled_surface() const { return 2 * get_surface(); }
};
How to read this definition ?
- You can define polymorphic behavior by introduced member functions with the keyword
virtual
. Hereget_surface()
anddescribe_object()
will obviously be implemented differently for a square than for a circle. When the function is invoked on an object, function corresponding to the real class of the object will be determined at runtime. - It makes no sense to define
get_surface()
for an abstract shape. This is why the function is followed by= 0
. This means that the function is pure virtual function. - A polymorphic class should always define a virtual destructor.
- You may define non virtual member functions. When these function will be invoked for an object, the function will be chosen depending on the class used at compile-time. Here
get_double_surface()
is defined in this way. - A class that contains at least one pure virtual function is an abstract class. Abstract classes cannot be instantiated. You may only have pointers or references of an abstract class type.
Derived classes
Once a polymorphic base class is defined you can derive it. For example:
class Square : public Shape {
Point top_left;
double side_length;
public:
Square (const Point& top_left, double side)
: top_left(top_left), side_length(side_length) {}
double get_surface() override { return side_length * side_length; }
void describe_object() override {
std::cout << "this is a square starting at " << top_left.x << ", " << top_left.y
<< " with a length of " << side_length << std::endl;
}
};
Some explanations:
- You can define or override any of the virtual functions of the parent class. The fact that a function was virtual in the parent class makes it virtual in the derived class. No need to tell the compiler the keyword
virtual
again. But it’s recommended to add the keywordoverride
at the end of the function declaration, in order to prevent subtle bugs caused by unnoticed variations in the function signature. - If all the pure virtual functions of the parent class are defined you can instantiate objects for this class, else it will also become an abstract class.
- You are not obliged to override all the virtual functions. You can keep the version of the parent if it suits your need.
Example of instantiation
int main() {
Square square(Point(10.0, 0.0), 6); // we know it's a square, the compiler also
square.describe_object();
std::cout << "Surface: " << square.get_surface() << std::endl;
Circle circle(Point(0.0, 0.0), 5);
Shape *ps = nullptr; // we don't know yet the real type of the object
ps = &circle; // it's a circle, but it could as well be a square
ps->describe_object();
std::cout << "Surface: " << ps->get_surface() << std::endl;
}
Found a mistake? Have a question or improvement idea?
Let me know.
Table Of Contents