Guide
1 min read18 headings
Inheritance in C++
Table of Contents
- What is Inheritance
- Basic Syntax
- Access Specifiers in Inheritance
- Constructor and Destructor Order
- Function Overriding
- Types of Inheritance
- Multiple Inheritance
- Best Practices
What is Inheritance
Inheritance allows creating new classes based on existing classes:
- Base class (parent): The class being inherited from
- Derived class (child): The class that inherits
Benefits
| Benefit | Description |
|---|---|
| Code Reuse | Don't repeat common functionality |
| Extensibility | Add new features to existing classes |
| Hierarchy | Model real-world relationships |
| Polymorphism | Enable uniform interfaces |
IS-A Relationship
// A Dog IS-A Animal
class Animal { };
class Dog : public Animal { };
// A Car IS-A Vehicle
class Vehicle { };
class Car : public Vehicle { };
Basic Syntax
class Base {
public:
void baseMethod() { }
};
class Derived : public Base { // Inherits from Base
public:
void derivedMethod() { }
};
// Usage
Derived d;
d.baseMethod(); // Inherited from Base
d.derivedMethod(); // Defined in Derived
Complete Example
class Animal {
protected:
string name;
int age;
public:
Animal(const string& n, int a) : name(n), age(a) {}
void eat() {
cout << name << " is eating" << endl;
}
void sleep() {
cout << name << " is sleeping" << endl;
}
};
class Dog : public Animal {
private:
string breed;
public:
Dog(const string& n, int a, const string& b)
: Animal(n, a), breed(b) {} // Call base constructor
void bark() {
cout << name << " says: Woof!" << endl;
}
void displayInfo() {
cout << name << " is a " << age << " year old " << breed << endl;
}
};
// Usage
Dog dog("Buddy", 3, "Labrador");
dog.eat(); // Inherited
dog.sleep(); // Inherited
dog.bark(); // Dog-specific
dog.displayInfo();
Access Specifiers in Inheritance
Three Inheritance Modes
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember; // Never inherited
};
class PublicDerived : public Base {
// publicMember remains public
// protectedMember remains protected
};
class ProtectedDerived : protected Base {
// publicMember becomes protected
// protectedMember remains protected
};
class PrivateDerived : private Base {
// publicMember becomes private
// protectedMember becomes private
};
Access Level Table
| Base Member | public Inheritance | protected Inheritance | private Inheritance |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | not accessible | not accessible | not accessible |
Most Common: Public Inheritance
// Public inheritance = IS-A relationship
class Shape {
public:
virtual void draw() = 0;
};
class Circle : public Shape { // Circle IS-A Shape
public:
void draw() override {
cout << "Drawing circle" << endl;
}
};
Protected Members
class Base {
protected:
int data; // Accessible in derived classes
public:
Base(int d) : data(d) {}
};
class Derived : public Base {
public:
Derived(int d) : Base(d) {}
void modify() {
data = 100; // OK: protected is accessible
}
int getData() const { return data; }
};
// Outside classes
Derived d(50);
// d.data = 10; // ERROR: protected
cout << d.getData(); // OK: through public method
Constructor and Destructor Order
Order of Execution
class Base {
public:
Base() { cout << "Base constructor" << endl; }
~Base() { cout << "Base destructor" << endl; }
};
class Derived : public Base {
public:
Derived() { cout << "Derived constructor" << endl; }
~Derived() { cout << "Derived destructor" << endl; }
};
Derived d;
// Output:
// Base constructor <- First
// Derived constructor <- Second
// Derived destructor <- First (reverse order)
// Base destructor <- Second
Calling Base Constructor
class Person {
protected:
string name;
int age;
public:
Person(const string& n, int a) : name(n), age(a) {
cout << "Person constructor" << endl;
}
};
class Student : public Person {
private:
string studentId;
public:
// Must call base constructor in initializer list
Student(const string& n, int a, const string& id)
: Person(n, a), studentId(id) { // Call Person first
cout << "Student constructor" << endl;
}
};
Default Base Constructor
class Base {
public:
Base() { cout << "Base default" << endl; }
Base(int x) { cout << "Base(" << x << ")" << endl; }
};
class Derived : public Base {
public:
// Implicitly calls Base()
Derived() {
cout << "Derived" << endl;
}
// Explicitly calls Base(int)
Derived(int x) : Base(x) {
cout << "Derived(" << x << ")" << endl;
}
};
Function Overriding
Basic Override
class Animal {
public:
void speak() {
cout << "Animal speaks" << endl;
}
};
class Dog : public Animal {
public:
// Override base class method
void speak() {
cout << "Dog barks" << endl;
}
};
Dog d;
d.speak(); // "Dog barks"
Calling Base Version
class Animal {
public:
void speak() {
cout << "Animal speaks" << endl;
}
};
class Dog : public Animal {
public:
void speak() {
Animal::speak(); // Call base version
cout << "Dog barks" << endl;
}
};
Dog d;
d.speak();
// Output:
// Animal speaks
// Dog barks
Virtual Functions (Polymorphism)
class Shape {
public:
virtual void draw() { // Virtual for polymorphism
cout << "Drawing shape" << endl;
}
virtual ~Shape() = default; // Virtual destructor
};
class Circle : public Shape {
public:
void draw() override { // Override keyword (C++11)
cout << "Drawing circle" << endl;
}
};
// Polymorphic behavior
Shape* shape = new Circle();
shape->draw(); // "Drawing circle" - calls Circle::draw()
delete shape;
override and final Keywords
class Base {
public:
virtual void foo() {}
virtual void bar() {}
void baz() {} // Not virtual
};
class Derived : public Base {
public:
void foo() override {} // OK: overrides Base::foo
// void bar(int) override; // ERROR: signature doesn't match
// void baz() override; // ERROR: Base::baz is not virtual
};
class Final : public Base {
public:
void foo() final {} // Cannot be overridden further
};
class TryOverride : public Final {
public:
// void foo() override; // ERROR: foo is final
};
Types of Inheritance
Single Inheritance
class Animal { };
class Dog : public Animal { }; // One base class
Multilevel Inheritance
class Animal { };
class Mammal : public Animal { };
class Dog : public Mammal { }; // Chain of inheritance
Hierarchical Inheritance
class Animal { };
class Dog : public Animal { }; // Multiple classes
class Cat : public Animal { }; // inherit from same base
class Bird : public Animal { };
Multiple Inheritance
class Flyable {
public:
virtual void fly() = 0;
};
class Swimmable {
public:
virtual void swim() = 0;
};
class Duck : public Flyable, public Swimmable {
public:
void fly() override { cout << "Duck flying" << endl; }
void swim() override { cout << "Duck swimming" << endl; }
};
Multiple Inheritance
Basic Syntax
class A {
public:
void methodA() { cout << "A" << endl; }
};
class B {
public:
void methodB() { cout << "B" << endl; }
};
class C : public A, public B {
public:
void methodC() { cout << "C" << endl; }
};
C c;
c.methodA(); // From A
c.methodB(); // From B
c.methodC(); // From C
The Diamond Problem
class Animal {
public:
int age;
};
class Mammal : public Animal { };
class Bird : public Animal { };
class Bat : public Mammal, public Bird {
// Has TWO copies of Animal::age!
};
Bat b;
// b.age = 5; // ERROR: ambiguous
b.Mammal::age = 5; // OK: specify which
b.Bird::age = 3; // Different copy!
Solution: Virtual Inheritance
class Animal {
public:
int age;
};
class Mammal : virtual public Animal { }; // virtual
class Bird : virtual public Animal { }; // virtual
class Bat : public Mammal, public Bird {
// Only ONE copy of Animal
};
Bat b;
b.age = 5; // OK: unambiguous
Interface-like Multiple Inheritance
// Best practice: Inherit from interfaces (pure abstract classes)
class Drawable {
public:
virtual void draw() = 0;
virtual ~Drawable() = default;
};
class Moveable {
public:
virtual void move(int x, int y) = 0;
virtual ~Moveable() = default;
};
class Sprite : public Drawable, public Moveable {
public:
void draw() override { /* ... */ }
void move(int x, int y) override { /* ... */ }
};
Best Practices
✅ Do
// 1. Use public inheritance for IS-A relationships
class Car : public Vehicle { }; // Car IS-A Vehicle
// 2. Use virtual destructors in base classes
class Base {
public:
virtual ~Base() = default;
};
// 3. Use override keyword
class Derived : public Base {
void method() override { }
};
// 4. Prefer composition over inheritance when appropriate
class Engine { };
class Car {
Engine engine; // Car HAS-A Engine
};
// 5. Keep inheritance hierarchies shallow
// Prefer: A -> B -> C (3 levels)
// Avoid: A -> B -> C -> D -> E -> F (6 levels)
// 6. Use protected for members that derived classes need
class Base {
protected:
int sharedData;
};
❌ Don't
// 1. Don't inherit just for code reuse
// Use composition instead
class NotAList : public vector<int> { }; // Bad
class HasAList { vector<int> data; }; // Better
// 2. Don't forget virtual destructors
class Base {
~Base() { } // BAD if inherited
};
// 3. Don't change method semantics in derived class
class Rectangle {
virtual int area() { return width * height; }
};
class Square : public Rectangle {
int area() override { return side * side; } // Different formula OK
// But don't change meaning entirely
};
// 4. Don't expose implementation through public inheritance
class Stack : public vector<int> { }; // Exposes vector's interface
// 5. Don't inherit from classes not designed for inheritance
class String : public std::string { }; // No virtual destructor!
Liskov Substitution Principle
Objects of a derived class should be usable wherever base class objects are expected:
void processAnimal(Animal& a) {
a.eat();
a.sleep();
}
Dog dog("Buddy", 3);
Cat cat("Whiskers", 2);
processAnimal(dog); // OK: Dog IS-A Animal
processAnimal(cat); // OK: Cat IS-A Animal
Quick Reference
// Base class
class Base {
public:
Base() { } // Constructor
virtual ~Base() { } // Virtual destructor
virtual void method() { } // Virtual method
protected:
int protectedData; // Accessible in derived
private:
int privateData; // Not accessible in derived
};
// Derived class
class Derived : public Base { // Public inheritance
public:
Derived() : Base() { } // Call base constructor
void method() override { } // Override virtual method
void useProtected() {
protectedData = 10; // OK: protected
}
};
// Multiple inheritance
class Multi : public Base1, public Base2 {
// Inherits from both
};
// Virtual inheritance (diamond problem)
class VDerived : virtual public Base {
// For diamond inheritance
};
Compile & Run
g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
./examples