Inheritance
By the end of this lesson you'll be able to build a class hierarchy with base and derived classes, call base constructors correctly, override behaviour with virtual functions, and call one method on many object types through a base pointer — the heart of flexible, extensible C++.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Think of inheritance like biology. Animal is the general category — every animal can eat and sleep. A Dog is an Animal, so it gets all those traits for free, and adds its own (barking). That "is-a" link is exactly what class Dog : public Animal means. Polymorphism is the next idea: if you ask a line-up of different animals to "speak", each makes its own sound — same instruction, different result. In C++ the virtual keyword is what makes that happen, deciding the right behaviour while the program runs.
Use protected for data a derived class needs to touch but the outside world shouldn't. private base members still exist in the derived object — they're just only reachable through the base's own public/protected methods.
1. Base & Derived Classes
A base class holds what's shared; a derived class adds what's special. You write class Derived : public Base — the public keyword gives you public inheritance , the normal "Derived is-a Base" relationship. The derived object contains the base part, so it can use the base's public and protected members as if they were its own. Read this worked example and run it.
Notice the constructor: Dog(string n, string b) : Animal(n), breed(b) . The base part must be built first, so you call the base constructor in the init list . If you don't, C++ tries to call Animal() with no arguments — and since Animal has no such constructor, that's a compile error. Now your turn: finish the Car class below.
2. Virtual Functions, override & Polymorphism
Polymorphism means "many forms": you call one method through a base pointer and get the right derived behaviour. The magic word is virtual . Mark a base method virtual to say "a child may replace me", then in the child write the same method with override . Because the choice is made while the program runs, this is called runtime polymorphism (or dynamic dispatch). The key rule: it only works through a base pointer or reference , never a plain value.
See how a->speak() runs Dog::speak for the dog and Cat::speak for the cat, even though a is an Animal* ? That's dynamic dispatch. Now add the virtual and override keywords yourself:
3. Abstract Classes & Pure Virtual Functions
Sometimes the base class has no sensible default — what's the area of a generic "Shape"? You make the function pure virtual by writing = 0 : virtual double area() const = 0; . That has two effects. First, every derived class must implement it. Second, the base becomes an abstract class — you can't create one directly, only its concrete children. Abstract classes are how C++ defines an interface.
When you delete an object through a base pointer , C++ needs to know which destructor to run. If the base destructor is not virtual , only the base part is destroyed — the derived part leaks, and the standard calls this undefined behaviour .
The rule is simple: any class with virtual functions should declare a virtual destructor. Often virtual ~Base() = default; is all you need.
No blanks this time — just a brief and an outline. Build an abstract Shape with a pure virtual area() , derive Circle and Rectangle , then loop over a vector<Shape*> and print each area. Check your output against the comments.
Practice quiz
What does 'class Dog : public Animal' express?
- Dog contains a copy of Animal's name
- Animal inherits from Dog
- A 'Dog is-a Animal' relationship (public inheritance)
- Dog and Animal are unrelated
Answer: A 'Dog is-a Animal' relationship (public inheritance). Public inheritance models the 'is-a' relationship. The Dog object contains the Animal part and can use Animal's public/protected members.
How does a derived constructor build the base part of the object?
- By calling the base constructor in the init list, e.g. Dog(string n) : Animal(n)
- It cannot
- By calling delete on the base
- Automatically with no syntax ever needed if the base has arguments
Answer: By calling the base constructor in the init list, e.g. Dog(string n) : Animal(n). The base part must be built first, so you call the base constructor in the init list. If the base has no default constructor, omitting this is a compile error.
What does the 'virtual' keyword in a base class enable?
- Faster compilation
- It makes the function private
- It prevents inheritance
- A derived class can replace the function through a base pointer (runtime polymorphism)
Answer: A derived class can replace the function through a base pointer (runtime polymorphism). Marking a base method virtual says 'a child may replace me'. The right override is then chosen at runtime through a base pointer or reference.
Why is writing 'override' on a derived method recommended?
- It makes the method faster
- The compiler errors if no matching base virtual exists, catching signature typos
- It is required for the code to compile
- It deletes the base version
Answer: The compiler errors if no matching base virtual exists, catching signature typos. override is free insurance: a mismatched signature becomes a compile error instead of silently creating a brand-new function that never overrides.
Through what must you call a virtual function to get polymorphic behaviour?
- A base pointer or reference
- A base value (plain object)
- A static_cast
- A global variable
Answer: A base pointer or reference. Dynamic dispatch works only through a base pointer (Animal*) or reference (Animal&). Copying into a plain base value loses polymorphism.
What is object slicing?
- Splitting a class into multiple files
- Deleting half an array
- Copying a derived object into a base VALUE, which drops the derived data and overrides
- A template specialisation
Answer: Copying a derived object into a base VALUE, which drops the derived data and overrides. Base b = derived; copies only the base part. The derived data and overrides are 'sliced off', so virtual calls run the base version.
What makes a function pure virtual, and what is its effect on the class?
- The 'final' keyword; it seals the class
- Writing '= 0'; the class becomes abstract and cannot be instantiated
- The 'static' keyword; it makes the class global
- Writing 'const'; it makes the class read-only
Answer: Writing '= 0'; the class becomes abstract and cannot be instantiated. virtual double area() const = 0; is pure virtual. A class with at least one pure virtual is abstract — only derived classes that implement it can be instantiated.
Why should a polymorphic base class declare a virtual destructor?
- For faster destruction
- It is purely stylistic
- To allow copying
- So 'delete base;' on a derived object runs the derived destructor too
Answer: So 'delete base;' on a derived object runs the derived destructor too. Without a virtual destructor, deleting a derived object through a base pointer runs only ~Base() — the derived part leaks. This is undefined behaviour.
Given Animal* a = new Dog("Rex"); with virtual speak(), what does a->speak() do?
- Calls Animal::speak
- Calls Dog::speak (the override), chosen at runtime
- Causes a compile error
- Calls both versions
Answer: Calls Dog::speak (the override), chosen at runtime. Because speak is virtual and a points to a Dog, dynamic dispatch runs Dog::speak — 'Rex says: Woof!' — even though a is an Animal*.
Why shouldn't you rely on a virtual function called from a base constructor?
- It is too slow
- It always crashes
- The derived part isn't built yet, so the BASE version runs, not the override
- Constructors cannot call functions
Answer: The derived part isn't built yet, so the BASE version runs, not the override. During the base constructor the derived part doesn't exist yet, so C++ calls the base version of any virtual. The same applies in destructors.