Use inheritance to model a substitutable relationship
A derived class contains a base subobject and can add its own state and behavior. Public inheritance commonly expresses “a derived object can be used as a base object”. Composition is often clearer when the relationship is simply “has a”.
Base construction and a derived method
#include
#include
#include
class Person {
std::string name_;
public:
explicit Person(std::string name) : name_{std::move(name)} { }
const std::string& name() const { return name_; }
};
class Student : public Person {
int roll_;
public:
Student(std::string name, int roll)
: Person{std::move(name)}, roll_{roll} { }
void print() const {
std::cout << roll_ << ' ' << name() << '\n';
}
};
int main() {
Student student{"Asha", 101};
student.print();
const Person& person = student;
std::cout << person.name() << '\n';
} Expected lines: 101 Asha and Asha. The Student constructor initializes the Person base first. It uses a public accessor rather than reaching into Person's private data.
Inheritance access modes
- Public: public base members remain public, and protected base members remain protected in the derived interface.
- Protected: public and protected base members become protected in the derived interface.
- Private: public and protected base members become private in the derived interface.
Private base members remain inaccessible directly to derived code in every mode. Omitting the inheritance mode defaults to private for class and public for struct.
Slicing and virtual destruction
Copying a derived object into a base object by value keeps only the base portion: this is slicing. Use a reference or suitable pointer when you need runtime polymorphism. If objects will be deleted through a base pointer, provide an appropriate virtual base destructor. The simple Person example does not dynamically allocate or delete through Person.
Prefer narrow base interfaces
Putting data in protected fields can tightly couple subclasses to an implementation. Private data with deliberate protected/public operations often protects invariants better. Do not inherit from a container just to reuse its storage; keeping the container as a member usually expresses ownership more clearly.
Practice
- Add a Teacher derived class with a subject field.
- Pass both Student and Teacher to a function taking const Person&.
- Attempt to access name_ directly from Student and explain the access error.
- Describe why a Car should contain an Engine rather than publicly inherit from Engine.