Introduction to Inheritance
A complete guide to code reuse, class hierarchies, virtual functions, and more — explained clearly with working examples.
Meaning of Inheritance
Inheritance in C++ is a feature where one class gets the properties and functions of another class. In simple words, it allows one class to reuse the code of another class. This helps in reducing repetition and makes programs easier to manage.
You can think of it like a child getting qualities from parents — the child does not need to create everything from zero; it simply uses what already exists.
In programming, this means we write common features in one class and reuse them in other classes. If many objects share similar behavior, we can write it once in a base class and reuse it in derived classes.
- Improves code reusability and reduces duplication.
- Makes programs more structured and organized.
- Helps divide large projects into smaller, manageable parts.
- Easy maintenance — updates to the base class automatically apply to derived classes.
Base Class and Derived Class
The main class that contains common properties and functions. It acts as a foundation for other classes.
The class that inherits from the base class. It can use all features of the base class and also add its own.
#include<iostream>
using namespace std;
class Animal {
public:
void eat() {
cout << "Animal eats" << endl;
}
};
class Dog : public Animal {
public:
void bark() {
cout << "Dog barks" << endl;
}
};
int main() {
Dog d;
d.eat(); // inherited from Animal
d.bark(); // Dog's own function
return 0;
}
Dog barks
Derived Class Constructors
A constructor is a special function that runs automatically when an object is created. It is used to initialize values.
#include<iostream>
using namespace std;
class Base {
public:
Base() {
cout << "Base Constructor Called" << endl;
}
};
class Derived : public Base {
public:
Derived() {
cout << "Derived Constructor Called" << endl;
}
};
int main() {
Derived d;
return 0;
}
Derived Constructor Called
Overriding Member Functions
Function overriding means defining the same function in both the base and derived class. The derived class version replaces the base class version when called on a derived object.
class Base {
public:
void show() {
cout << "This is Base class function" << endl;
}
};
class Derived : public Base {
public:
void show() { // overrides Base::show()
cout << "This is Derived class function" << endl;
}
};
int main() {
Derived d;
d.show();
return 0;
}
Which Function is Called — Virtual Functions
When using a base class pointer, which version of a function gets called depends on whether the function is declared virtual.
Base* b; Derived d; b = &d; b->show(); // Calls BASE version ⚠️
virtual void show() { ... }
// in Base class
Base* b;
Derived d;
b = &d;
b->show();
// Calls DERIVED version ✅
virtual keyword enables runtime polymorphism — the correct function is chosen at runtime based on the actual object type, not the pointer type.Class Hierarchy
Class hierarchy means arranging classes in a tree-like structure using inheritance. It shows the relationship between classes clearly.
Person → Student → Graduate
Person → Teacher
This creates a structured system where all classes are connected through a logical parent–child chain.
Types of Inheritance
Single Inheritance
One derived class inherits from one base class.A → B
Multilevel Inheritance
A chain of inheritance across multiple levels.A → B → C
Multiple Inheritance
One derived class inherits from multiple base classes.A, B → C
Hierarchical Inheritance
Multiple derived classes inherit from one base.A → B, A → C
Hybrid Inheritance
A combination of two or more types of inheritance.
class A {
public:
void show() { cout << "Class A" << endl; }
};
class B : public A {};
int main() {
B obj;
obj.show(); // Output: Class A
}
class A {
public:
void showA() { cout << "Class A" << endl; }
};
class B : public A {};
class C : public B {};
int main() {
C obj;
obj.showA(); // Output: Class A
}
class A {
public:
void showA() { cout << "Class A" << endl; }
};
class B {
public:
void showB() { cout << "Class B" << endl; }
};
class C : public A, public B {};
int main() {
C obj;
obj.showA(); // Class A
obj.showB(); // Class B
}
class A {
public:
void show() { cout << "Class A" << endl; }
};
class B : public A {};
class C : public A {};
int main() {
B obj1; C obj2;
obj1.show(); // Class A
obj2.show(); // Class A
}
class A {
public:
void showA() { cout << "Class A" << endl; }
};
class B : public A {};
class C : public A {};
class D : public B, public C {};
int main() {
D obj;
obj.B::showA(); // Resolving ambiguity
// Output: Class A
}
Multiple Inheritance and Ambiguity
When two base classes have a function with the same name, the compiler gets confused about which one to call.
obj.A::show(); // calls A's version obj.B::show(); // calls B's version
Aggregation
Aggregation means one class contains an object of another class. It represents a "has-a" relationship, as opposed to the "is-a" relationship in inheritance.
#include<iostream>
using namespace std;
class Engine {
public:
void start() {
cout << "Engine starts" << endl;
}
};
class Car {
Engine e; // Car "has-a" Engine
public:
void startCar() {
e.start();
cout << "Car starts" << endl;
}
};
int main() {
Car c;
c.startCar();
}
Car starts
Frequently Asked Questions
::.🎯 Conclusion
Inheritance in C++ becomes very easy once you understand the basic idea of reusing code. Concepts like base class, derived class, constructors, and the different types of inheritance help you write better programs. The key is to practice and understand how classes are connected — once you see the relationships, everything becomes simple and logical.
Introduction to Pointers
Master one of C++'s most powerful features — understand memory addresses, pointer operations, arrays, functions, and dynamic memory allocation.
What are Pointers?
Pointers are one of the most important concepts in C++. A pointer is a variable that stores the address of another variable. Instead of storing a value directly, it stores the location where the value is stored in memory.
Think of memory like a set of houses, and each house has an address. A normal variable stores the value inside the house, while a pointer stores the address of that house. This allows us to access and modify data indirectly.
- Help in efficient memory usage and faster program execution.
- Used to pass large data to functions without copying it.
- Essential for dynamic memory allocation.
- Power advanced data structures like linked lists.
- Without pointers, many advanced C++ features would not be possible.
Addresses and Pointers
Every variable in C++ is stored in memory, and each memory location has a unique address — a number usually shown in hexadecimal format. We can access this address using special operators.
A pointer is declared using the * symbol.
int x = 10; // x stores value 10 int *ptr; // ptr is a pointer to int ptr = &x; // ptr stores address of x // Now: // x → 10 // ptr → address of x (e.g. 0x61ff08) // *ptr → 10 (value at that address)
| Operator | Name | Purpose | Example |
|---|---|---|---|
& |
Address-of | Gets the memory address of a variable | &x |
* |
Dereference | Gets the value stored at a pointer's address | *ptr |
-> |
Arrow | Access object members via pointer | ptr->marks |
Address-of Operator (&)
The & operator is used to get the address of a variable. It is called the address-of operator.
#include<iostream>
using namespace std;
int main() {
int x = 5;
cout << "Value of x: " << x << endl;
cout << "Address of x: " << &x << endl;
}
Address of x: 0x61ff08
Pointers and Arrays
In C++, the name of an array itself acts like a pointer — it stores the address of the first element. This means arrays and pointers are closely related.
arr → address of first element |
arr[0] → first value
#include<iostream>
using namespace std;
int main() {
int arr[3] = {10, 20, 30};
int *ptr = arr; // ptr points to arr[0]
cout << "First element: " << *ptr << endl;
cout << "Second element: " << *(ptr + 1) << endl;
cout << "Third element: " << *(ptr + 2) << endl;
}
Second element: 20
Third element: 30
Pointers and Functions
Pointers can be passed to functions. This allows the function to change the original value in the caller's scope — unlike normal variable passing which only copies the value.
#include<iostream>
using namespace std;
void change(int *p) {
*p = 50; // modifies the original variable
}
int main() {
int x = 10;
change(&x); // pass address of x
cout << "Value of x: " << x << endl;
}
Pointers and C-Type Strings
C-type strings are character arrays ending with a null terminator \0. A pointer can traverse each character of the string one by one.
#include<iostream>
using namespace std;
int main() {
char str[] = "Hello";
char *ptr = str;
cout << "String: " << ptr << endl;
while(*ptr != '\0') { // loop until null terminator
cout << *ptr << " ";
ptr++; // move to next character
}
}
H e l l o
Memory Management (new and delete)
C++ allows us to allocate memory during runtime using new and free it using delete.
new
Reserves memory on the heap at runtime and returns a pointer to it.
delete
Frees the previously allocated memory to prevent memory leaks.
#include<iostream>
using namespace std;
int main() {
int *ptr = new int; // allocate memory on heap
*ptr = 100;
cout << "Value: " << *ptr << endl;
delete ptr; // free the memory
}
delete after new to avoid memory leaks — memory that is allocated but never freed.Pointers to Objects
Pointers can also store the address of objects. This is particularly useful in object-oriented programming where objects are passed around efficiently.
#include<iostream>
using namespace std;
class Student {
public:
int marks;
void display() {
cout << "Marks: " << marks << endl;
}
};
int main() {
Student s;
Student *ptr;
ptr = &s; // pointer to object s
ptr->marks = 90; // use -> to access members
ptr->display();
}
-> to access members of an object through a pointer. It is equivalent to (*ptr).marks.Frequently Asked Questions
& gives the memory address of a variable. Example: &x returns the address where x is stored.new dynamically allocates memory on the heap at runtime. delete releases that memory. Always pair them to avoid memory leaks.-> instead of the dot operator.🎯 Conclusion
Pointers in C++ may seem difficult at first, but they become easy with practice. They help us work with memory directly and make programs faster and more efficient. Concepts like arrays, functions, and objects become more powerful when combined with pointers. The key is to understand how memory works and practice small programs regularly.
Virtual Functions & More
Explore runtime polymorphism, friend functions, static functions, the this pointer, and dynamic type information — all explained with clear examples.
Virtual Functions
Runtime polymorphism — correct function chosen by object type, not pointer type.
Friend Functions
Non-member functions granted special access to private class data.
Static Functions
Class-level functions shared across all objects, callable without an instance.
This Pointer
Special pointer that always refers to the current object inside a member function.
Dynamic Type Info
Identifying the real type of an object at runtime using typeid.
Virtual Functions
A virtual function is a function in the base class declared using the keyword virtual. It is used to achieve runtime polymorphism — meaning the function call is decided at runtime, not at compile time.
It helps when we use a base class pointer to call a derived class function. In simple words, virtual functions allow the program to decide which function to call based on the object type, not the pointer type.
virtual, the base class version is always called through a base pointer — even if the object is derived.Base* b = &d; b->show(); // Always calls Base::show() ⚠️
virtual void show() { ... }
// in Base class
Base* b = &d;
b->show();
// Calls Derived::show() ✅
#include<iostream>
using namespace std;
class Base {
public:
virtual void show() {
cout << "Base class show function" << endl;
}
};
class Derived : public Base {
public:
void show() {
cout << "Derived class show function" << endl;
}
};
int main() {
Base* b;
Derived d;
b = &d;
b->show(); // Calls Derived version due to virtual
}
Friend Functions
A friend function is a function that is not a member of a class but can access its private and protected data. It is declared using the keyword friend inside the class.
Normally, private data cannot be accessed outside the class. But friend functions are special — they can access that data directly. They are useful when two or more classes need to share data.
friend keyword but defined outside — just like a regular function.#include<iostream>
using namespace std;
class Test {
private:
int x;
public:
Test() {
x = 10;
}
friend void display(Test t); // friend declaration
};
void display(Test t) { // defined outside
cout << "Value of x: " << t.x << endl; // can access private x
}
int main() {
Test t;
display(t);
}
Static Functions
A static function belongs to the class, not to any object. It is shared by all objects of the class and can only access static data members.
You can call a static function using the class name directly — no object creation needed.
Demo obj; obj.show(); // requires an object ⚠️
Demo::show(); // no object needed ✅
#include<iostream>
using namespace std;
class Demo {
public:
static void show() {
cout << "Static function called" << endl;
}
};
int main() {
Demo::show(); // called using class name, no object
}
Assignment and Copy Initialization
Assignment means giving a value to a variable after it is already created.
int a; // variable created a = 10; // value assigned later
Copy initialization means initializing a variable using another variable or value at the time of declaration.
int a = 10; // value given at declaration int b = a; // b initialized by copying a
int a; a = 10; // Value given AFTER creation
int a = 10; int b = a; // Value given AT declaration
This Pointer
The this pointer is a special pointer that automatically points to the current object. It is implicitly available inside all non-static member functions.
It is especially useful when a member variable and a parameter share the same name — this-> distinguishes the object's member from the local parameter.
this->x = x means: set this object's x to the value of the parameter x.#include<iostream>
using namespace std;
class Demo {
int x;
public:
void setValue(int x) {
this->x = x; // this->x is the member, x is the parameter
}
void show() {
cout << "Value of x: " << x << endl;
}
};
int main() {
Demo d;
d.setValue(50);
d.show();
}
Dynamic Type Information
Dynamic type information means finding the actual type of an object during runtime. This is useful when working with base class pointers that point to derived objects.
C++ provides the typeid operator (from the <typeinfo> header) to get the real type of an object at runtime.
typeid(*b).name() returns the actual type of the object being pointed to — not the type of the pointer itself.#include<iostream>
#include<typeinfo>
using namespace std;
class Base {};
class Derived : public Base {};
int main() {
Base* b = new Derived; // Base pointer → Derived object
cout << typeid(*b).name() << endl; // reveals actual type
}
Frequently Asked Questions
virtual keyword that is resolved at runtime based on the actual object type, enabling runtime polymorphism.friend keyword.typeid operator from the <typeinfo> header.🎯 Conclusion
These advanced concepts in C++ may look difficult at first, but they become easy when you understand their purpose. Virtual functions help in runtime decisions, friend functions allow controlled access, and static functions provide shared behavior. The this pointer helps manage current object data, while dynamic type information helps identify objects during execution. Practice small programs first, then move to complex ones — and your C++ knowledge will grow much stronger.

0 Comments
If you have any doubts, Please let me know