Polymorphism lets code use a common interface while behavior follows an object's actual type. Inheritance earns its place when classes share a meaningful is-a relationship, not merely a few reusable methods. Reusing unrelated behavior creates awkward names, special-case handling, and objects that cannot substitute for one another. section 7.7
Listing 7.10 A simple inheritance hierarchy
class Person {
std::string name;
int age;
};
class Student : public Person {
double gpa;
};
A Person–Student hierarchy shows how a derived object contains base and derived data and can be viewed through either type. section 7.7
Accessing an object through a base reference or pointer exposes the base interface while preserving derived behavior. Storing derived objects as base-class values instead slices away the derived part, so polymorphic collections use pointers or references. A better design gives genuinely different classes a shared interface, such as Moveable, with operations each class implements meaningfully. section 7.7 section 8.8
Listing 7.13 Using an interface-like class
class Moveable { #1
public:
virtual void move(int) = 0;
virtual double getPosition() = 0;
};
class Square : public Moveable {
private:
double side;
double offset;
public:
Square(double side) : side(side), offset(0) {}
void move(int n) { this->offset += n*side; } #2
double getPosition() { return offset; }
double area() { return side*side; }
};
class Horse : public Moveable {
private:
double height;
double position;
public:
Horse(double height) : height(height), position(0) {}
void move(int offset) { position += offset; } #3
double getPosition() { return position; }
};
int main() {
std::vector<Moveable*> movers; #4
movers.push_back(new Square(1));
movers.push_back(new Horse(15));
for (int i = 0; i < movers.size(); ++i) {
movers[i]->move(2);
std::cout << "Mover moved " << movers[i]->getPosition() << " units \n";
}
return 0;
}
The Moveable example places Square and Horse behind one common interface, allowing one collection and one movement loop without type-specific casts. section 7.7
Treat polymorphic hierarchies as contracts that must remain correct throughout their object lifetimes.
- Use inheritance for substitutable is-a relationships; separate unrelated classes even when their methods look similar. section 7.7
- Give a polymorphic base class a virtual destructor when derived objects may be deleted through base pointers; otherwise destruction can leak resources and produce undefined behavior. section 8.8
- Throw exceptions by value and catch them by reference to avoid pointer-lifetime problems, reduce copying, and preserve overridden behavior. section 10.9
- Make derived assignment update the base portion as well as derived data; otherwise copying can leave the object's inherited state unchanged. section 8.7
Deleting through a base pointer
A Shape pointer refers to a Square, and area() dispatches correctly. If Shape's destructor is non-virtual, deleting the pointer calls only ~Shape and leaks Square's resource. Making the destructor virtual produces the expected ~Square followed by ~Shape destruction order. section 8.8








