Inheritance Basics
Learn how to create derived classes that inherit properties and behaviors from base classes
Learn how to create hierarchies of related classes where derived classes inherit and extend functionality from base classes.
A Simple Example
#include <iostream>
#include <string>
class Animal {
protected:
std::string name;
int age;
public:
Animal(std::string name, int age) : name{name}, age{age} {
std::cout << "Animal constructor: " << name << "\n";
}
void eat() {
std::cout << name << " is eating" << "\n";
}
void sleep() {
std::cout << name << " is sleeping" << "\n";
}
void displayInfo() {
std::cout << "Name: " << name << ", Age: " << age << "\n";
}
};
class Dog : public Animal {
private:
std::string breed;
public:
Dog(std::string name, int age, std::string breed)
: Animal{name, age}, breed{breed} {
std::cout << "Dog constructor: " << name << "\n";
}
void bark() {
std::cout << name << " says: Woof! Woof!" << "\n";
}
void displayBreed() {
std::cout << name << " is a " << breed << "\n";
}
};
class Cat : public Animal {
private:
bool isIndoor;
public:
Cat(std::string name, int age, bool indoor)
: Animal{name, age}, isIndoor{indoor} {
std::cout << "Cat constructor: " << name << "\n";
}
void meow() {
std::cout << name << " says: Meow!" << "\n";
}
void displayLocation() {
std::cout << name << " is " << (isIndoor ? "indoor" : "outdoor") << "\n";
}
};
int main() {
Dog dog{"Buddy", 3, "Golden Retriever"};
dog.displayInfo(); // Inherited from Animal
dog.eat(); // Inherited from Animal
dog.bark(); // Dog's own method
dog.displayBreed();
std::cout << "\n";
Cat cat{"Whiskers", 2, true};
cat.displayInfo(); // Inherited from Animal
cat.sleep(); // Inherited from Animal
cat.meow(); // Cat's own method
cat.displayLocation();
return 0;
}
Breaking It Down
Base Class Declaration
- What it does: The Animal class defines common properties (name, age) and behaviors (eat, sleep)
- protected members: Accessible to derived classes but not to outside code
- public methods: Interface that all animals share
- Remember: Design the base class to contain what all derived classes have in common
Derived Class Syntax: class Dog : public Animal
-
The colon
:indicates inheritance from Animal -
publicinheritance means public members stay public in Dog - Dog automatically gets all Animal members and methods
- Remember: Use public inheritance for "is-a" relationships (Dog is-a Animal)
Constructor Initialization List
-
Derived constructor must call base constructor:
Animal{name, age} - Base constructor runs first, then derived constructor
- Base constructor initializes base class members
- Remember: You cannot initialize base class members directly in derived constructor
Adding Specialized Behavior
- Dog adds bark() method and breed data member
- Cat adds meow() method and isIndoor data member
- Each derived class keeps common functionality and adds its own
- Remember: Inheritance promotes code reuse while allowing specialization
Why This Matters
- Inheritance is about modeling real-world relationships in code. A Dog is an Animal, a Manager is an Employee, a SavingsAccount is a BankAccount.
- Instead of duplicating common code, you inherit it from a base class and add specialized behavior. This makes your code more maintainable - fix a bug in the base class, and all derived classes benefit.
- It's foundational for building extensible systems and implementing polymorphism.
Critical Insight
When you create a derived class object, C++ calls constructors from the top down - base class first, then derived class. When destroying, it's reverse - derived destructor first, then base. This ensures the base class part is ready before the derived class constructor runs:
class Base {
public:
Base() { std::cout << "1. Base constructed\n"; }
~Base() { std::cout << "4. Base destroyed\n"; }
};
class Derived : public Base {
public:
Derived() { std::cout << "2. Derived constructed\n"; }
~Derived() { std::cout << "3. Derived destroyed\n"; }
};
int main() {
Derived d; // Output: 1, 2 (construction)
// When d goes out of scope: 3, 4 (destruction)
}
Think of it like building a house: you need the foundation (base) before the walls (derived).
Best Practices
Use public inheritance for "is-a" relationships: When Dog is-a Animal, use class Dog : public Animal. This is the most common form.
Make shared data protected, not public: Base class members that derived classes need should be protected so external code cannot access them directly.
Always call base constructor in initialization list: Derived constructors must initialize the base class using the initialization list, not in the body.
Design base classes for inheritance: Include a virtual destructor if your class will be used polymorphically.
Common Mistakes
Forgetting to call base constructor: Derived class constructors must explicitly call the base constructor in the initialization list.
Using private instead of protected: Private base members are not accessible in derived classes, even with inheritance.
Incorrect inheritance syntax: Must specify access level in inheritance, like class Dog : public Animal, not just class Dog : Animal.
Trying to initialize base members directly: You cannot assign to base class members in the derived constructor body - must use base constructor.
Debug Challenge
This Dog class has a bug in its constructor. Click the highlighted line to fix it:
Quick Quiz
- What order are constructors called when creating a derived class object?
- What access specifier should base class members use if derived classes need direct access?
- What does a derived class inherit from its base class?
Practice Playground
Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.
Output:
Error:
Lesson Progress
- Fix This Code
- Quick Quiz
- Practice Playground - run once