Introduction
Imagine someone asks you to build software for a zoo.
You identity the following animals:
- Dog
- Cat
- Elephant
- Lion
- Tiger
- Horse
You begin writing classes.
class Dog
{
public:
void eat() {}
void sleep() {}
void breathe() {}
};
class Cat
{
public:
void eat() {}
void sleep() {}
void breathe() {}
};
class Lion
{
public:
void eat() {}
void sleep() {}
void breathe() {}
};After writing only three classes, something feels wrong.
The code is almost identical.
If you continue, you will duplicate the same function dozens of times.
Now consider another example:
Vehicles.
- Car
- Bus
- Truck
- Motorcyle
Again:
class Car
{
public:
void startEngine() {}
void stopEngine() {}
};
class Bus
{
public:
void startEngine() {}
void stopEngine() {}
};
class Truck
{
public:
void startEngine() {}
void stopEngine() {}
};The same pattern appears.
We have many objects that share common behavior.
This problem existed long before C++.
Early software systems often duplicated logic across multiple modules, making maintenance difficult and error-prone.
Inheritance was introduced to solve this problem.
Historical Context
To understand inheritance, we must first understand the programming world before object-oriented programming.
Procedural Programming Era
Languages like C focused on functions.
Data and behavior were separate.
For example:
struct Employee
{
char name[50];
int age;
};
void printEmployee(Employee* e);
void calculateSalary(Employee* e);
void promote(Employee* e);As systems grew, many structures became similar.
For example:
Employee
Manager
Developer
Tester
InternEach structure contained common information:
Name
Age
IDProgrammers repeatedly copied fields and functions.
This led to:
- Massive code duplication.
- Inconsistent behavior.
- Difficult maintenance.
The question became:
“Why are we rewriting the same logic over and over?”
Object-oriented programming answered this with inheritance.
What Is Inheritance?
Definition
Inheritance is a mechanism by which one class acquires the properties and behaviors of another class.
The existing class is called the base class (or parent class).
The new class is called the derived class (or child class).
Textually:
Animal
▲
│
┌────────┴────────┐
│ │
Dog CatInstead of writing common functionality multiple times.
class Animal
{
public:
void eat()
{
std::cout << "Eating\n";
}
void sleep()
{
std::cout << "Sleeping\n";
}
};Dog inherits it:
class Dog : public Animal
{
};Cat inherits it:
class Cat : public Animal
{
};Usage:
Dog dog;
dog.eat();
dog.sleep();
Cat cat;
cat.eat();Understanding Generalization
Many beginners think inheritance and generalization are identical.
They are related, but not the same.
This distinction is critical.
Generalization
Generalization is a design activity.
It happens during analysis.
We ask:
“What characteristics are common among these objects”
Consider:
Dog
Cat
Horse
TigerAll of them:
- Eat
- Sleep
- Breathe
- Reproduce
We generalize them into:
AnimalDiagram:
Dog
Cat
Horse
Tiger
↓
AnimalGeneralization is a way of discovering abstractions.
Inheritance
Inheritance is the programming mechanism used to implement that abstraction.
Generalization exists in the problem domain.
Inheritance exists in the programming language.
A useful mental model is:
Generalization
↓
Design Decision
↓
Inheritance
↓
ImplementationThe “Is-A” Relationship
Inheritance represents an Is-A relationship.
Ask yourself:
“Is this object a specialized version of another object?”
Examples:
Dog IS-A Animal
Cat IS-A Animal
Bus IS-A Vehicle
Square IS-A Shape
CheckingAccount IS-A BankAccountThese are valid inheritance relationships.
Now consider:
Engine IS-A CarNo.
An engine is part of a car.
That's not inheritance.
It's composition.
Similarly:
Student IS-A UniversityWrong.
A student belongs to a university.
Not inheritance.
Another example:
Keyboard IS-A ComputerWrong.
The keyboard is part of a computer.
Always ask the Is-A question.
If the answer is "No,", inheritance is probably incorrect.
Mental Model: Specialization, Not Duplication
Many people learn inheritance as:
“A way to reuse code.”
While this is true, it is not the most important reason to use inheritance.
The deeper purpose is specialization.
Think of inheritance as answering the question:
“How is this concept a more specialized version of another concept?”
Code reuse is a consequence – not the primary goal.
If your only reason for inheritance is “to avoid duplicate code”, you are likely to create brittle class hierarchies.
Professional designer first ask:
- Is there a true Is-A relationship?
- Does the derived class preserve the meaning of the base class?
- Will this hierarchy remain valid as the software evolves?
If the answer to any of these is “no”, inheritance is probably the wrong tool.
Basic Syntax of Inheritance
The general syntax is:
class DerivedClass : access_specifier BaseClass
{
// Additional members
};Example:
class Animal
{
public:
void eat()
{
std::cout << "Eating...\n";
}
};
class Dog : public Animal
{
};Usage:
Dog dog;
dog.eat();Output:
Eating...Notice something interesting.
We never wrote an eat() function inside Dog.
Yet it works.
Why?
Because Dog inherits it from Animal.
Visualizing the Relationship
Although Dog contains no explicit members:
class Dog : public Animal
{
};You can mentally think of it like this:
Dog
-----------------------
Inherited:
eat()
-----------------------Or, if Animal also had data:
class Animal
{
protected:
std::string name;
int age;
public:
void eat();
void sleep();
};Then Dog conceptually becomes:
Dog
--------------------------------
Inherited Data
name
age
--------------------------------
Inherited Behavior
eat()
sleep()
--------------------------------The derived object contains the base object as part of its memory layout.
Constructors and Inheritance
One of the biggest misconceptions is:
“Constructors are inherited.”
They are not.
Consider:
class Animal
{
public:
Animal()
{
std::cout << "Animal created\n";
}
};
class Dog : public Animal
{
};Usage:
Dog dog;Output:
Animal createdDid Dog inherit the constructor?
No.
What happened?
Before constructing the Dog part, C++ first constructs the Animal part.
Construction order:
Create Dog
↓
Construct Animal
↓
Construct DogThink of building a house.
You don't build the roof first.
You build the foundation.
The base class is the foundation.
Constructor Chaining
Suppose:
class Animal
{
public:
Animal()
{
std::cout << "Animal\n";
}
};
class Dog : public Animal
{
public:
Dog()
{
std::cout << "Dog\n";
}
};Execution:
Dog dog;Output:
Animal
DogAlways remember.
Base constructors execute before derived constructors.
Passing Parameters to the Base Class
Suppose the base class needs information.
class Animal
{
protected:
std::string name;
public:
Animal(std::string n)
: name(n)
{
}
};The derived class must explicitly call it.
class Dog : public Animal
{
public:
Dog(std::string n)
: Animal(n)
{
}
};Usage:
Dog dog("Buddy");Execution:
Animal("Buddy")
↓
Dog("Buddy")The derived constructor initializes the base constructor.
Destruction Order
Construction proceeds.
Animal
↓
DogDestruction proceeds in reverse.
Dog
↓
AnimalExample:
class Animal
{
public:
~Animal()
{
std::cout << "Animal destroyed\n";
}
};
class Dog : public Animal
{
public:
~Dog()
{
std::cout << "Dog destroyed\n";
}
};Output:
Dog destroyed
Animal destroyedWhy?
Because C++ destroys objects in the opposite order in which they were created.
Access Specifiers in Inheritance
Remember:
Classes already have access specifiers.
public
protected
privateInheritance introduces another access specifier:
class Dog : public AnimalNotice the extra public.
That is called the inheritance mode.
C++ supports three modes:
public inheritance
protected inheritance
private inheritanceEach changes the accessibility of inherited members.
Public Imheritance
class Animal
{
public:
void eat();
protected:
int age;
private:
int secret;
};
class Dog : public Animal
{
};Accessibility becomes:
| Animal | Dog |
|---|---|
| public | public |
| protected | protected |
| private | inaccessible |
Nothing changes except that private members remain inaccessible.
This module a genuine Is-A relationship.
Example:
Dog dog;
dog.eat();Protected Inheritance
class Dog : protected Animal
{
};Transformation:
| Animal | Dog |
|---|---|
| public | protected |
| protected | protected |
| private | inaccessible |
Notice:
Everything public becomes protected.
Outside users cannot access it.
Example:
Dog dog;
dog.eat(); // ErrorInside Dog, however:
class Dog : protected Animal
{
public:
void test()
{
eat();
}
};This works.
Private Inheritance
class Dog : private Animal
{
};Transformation:
| Animal | Dog |
|---|---|
| public | private |
| protected | private |
| private | inaccessible |
Everything becomes private.
Outside code cannot access inherited members.
Leave a comment
Your email address will not be published. Required fields are marked *
