Inheritance lets a derived class acquire and extend behavior from a base class, but code reuse alone is not a sound reason to introduce it. Public inheritance should express an is-a relationship: wherever a base object is required, the derived object must remain substitutable. Poor hierarchies create exceptions, obscure behavior, and maintenance work. section 7.7 section 8.1
Treat inheritance as a correctness and maintenance decision, not merely a reuse technique:
- Check the Liskov substitution principle before deriving one class from another; apparent similarities do not establish an is-a relationship. section 7.7
- Remember that a derived object combines the data parts of its base and derived classes, so constructors, destructors, and operators must manage every part. section 8.7
- When a polymorphic base can be deleted through a pointer, provide a virtual destructor; otherwise deletion has undefined behavior and may skip derived cleanup. section 8.8
- Avoid duplicating base knowledge in overriding methods; call an appropriate base implementation when it forms part of the derived class's basis. section 7.5
The derived assignment that forgets its base
A Student is a Person with additional state. An assignment operator that copies only gpa leaves the destination's inherited name unchanged: assigning Thelma to Louise produces two different names with the same grade point average. Delegate the base portion first, then copy the derived portion: Person::operator=(o); gpa = o.gpa;. This pattern matters beyond explicit assignments because copying can occur through vector or array operations. section 8.7
The base pointer that deletes incorrectly
Shape is polymorphic because area is virtual. Creating a Square through Shape* and deleting that pointer requires Shape's destructor to be virtual. Without it, the output shows only ~Shape; with the virtual destructor, destruction proceeds through ~Square and then ~Shape. The hierarchy's base-class design therefore affects every derived type. 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;
}
Compare unrelated Square and Horse classes through a small Moveable interface, rather than forcing inheritance from a misleading common implementation class. section 7.7


















