C++ Object-Oriented Programming

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.

Importance of Inheritance
  • 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

Base Class (Parent Class)

The main class that contains common properties and functions. It acts as a foundation for other classes.

Derived Class (Child Class)

The class that inherits from the base class. It can use all features of the base class and also add its own.

Example Program
animal_dog.cpp C++
#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;
}
▶ Output
Animal eats
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.

⚡ The Base constructor always runs first, followed by the Derived constructor — regardless of declaration order.
constructors.cpp C++
#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;
}
▶ Output
Base Constructor Called
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.

overriding.cpp C++
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;
}
▶ Output
This is Derived class function
🎯

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.

Without Virtual
Base* b;
Derived d;
b = &d;
b->show();
// Calls BASE version ⚠️
▶ Output
Base function
With Virtual
virtual void show() { ... }
// in Base class

Base* b;
Derived d;
b = &d;
b->show();
// Calls DERIVED version ✅
▶ Output
Derived function
💡 The 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.

Real-world example:
Person → Student → Graduate
Person → Teacher

This creates a structured system where all classes are connected through a logical parent–child chain.

🧩

Types of Inheritance

TYPE 01

Single Inheritance

One derived class inherits from one base class.
A → B

TYPE 02

Multilevel Inheritance

A chain of inheritance across multiple levels.
A → B → C

TYPE 03

Multiple Inheritance

One derived class inherits from multiple base classes.
A, B → C

TYPE 04

Hierarchical Inheritance

Multiple derived classes inherit from one base.
A → B, A → C

TYPE 05

Hybrid Inheritance

A combination of two or more types of inheritance.

1. Single Inheritance
single.cppC++
class A {
public:
    void show() { cout << "Class A" << endl; }
};
class B : public A {};

int main() {
    B obj;
    obj.show();   // Output: Class A
}
2. Multilevel Inheritance
multilevel.cppC++
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
}
3. Multiple Inheritance
multiple.cppC++
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
}
4. Hierarchical Inheritance
hierarchical.cppC++
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
}
5. Hybrid Inheritance
hybrid.cppC++
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.

Solution: Use the scope resolution operator to specify which class's function to call.
ambiguity.cppC++
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.

aggregation.cppC++
#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();
}
▶ Output
Engine starts
Car starts

Frequently Asked Questions

01 What is inheritance?
It is a method of reusing code from one class in another. A derived class inherits all public and protected members of its base class.
02 What are the types of inheritance?
Single, Multilevel, Multiple, Hierarchical, and Hybrid inheritance.
03 What is function overriding?
Redefining a base class function in the derived class with the same name and signature so the derived version takes precedence.
04 What is ambiguity in inheritance?
Confusion that arises in multiple inheritance when two or more base classes have a function with the same name. Solved using the scope resolution operator ::.
05 What is aggregation?
When one class contains an object of another class as a member, representing a "has-a" relationship (e.g., a Car has an Engine).

🎯 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.

C++ Memory & Pointers

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.

Why Use Pointers?
  • 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.

0x61ff08
10
int x = 10
0x61ff0c
0x61ff08
int *ptr = &x
0x61ff10
free memory
Pointer Declaration

A pointer is declared using the * symbol.

pointer_decl.cpp C++
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)
Key Operators
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.

address_of.cpp C++
#include<iostream>
using namespace std;

int main() {
    int x = 5;
    cout << "Value of x:   " << x  << endl;
    cout << "Address of x: " << &x << endl;
}
▶ Output
Value of x: 5
Address of x: 0x61ff08
💡 The actual address value will vary each time the program runs — it depends on where the OS places the variable in memory.
📦

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.

Array pointer relationship:
arr → address of first element  |  arr[0] → first value
pointer_array.cpp C++
#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;
}
▶ Output
First element: 10
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.

pointer_function.cpp C++
#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;
}
▶ Output
Value of x: 50
👉 The function changes the original value using the pointer — this is called pass by pointer.
🔤

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.

pointer_string.cpp C++
#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
    }
}
▶ Output
String: Hello
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.

ALLOCATE

new

Reserves memory on the heap at runtime and returns a pointer to it.

DEALLOCATE

delete

Frees the previously allocated memory to prevent memory leaks.

memory_mgmt.cpp C++
#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
}
▶ Output
Value: 100
⚠️ Always use 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.

pointer_object.cpp C++
#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();
}
▶ Output
Marks: 90
💡 Use the arrow operator -> to access members of an object through a pointer. It is equivalent to (*ptr).marks.

Frequently Asked Questions

01 What is a pointer in simple words?
A pointer is a variable that stores the memory address of another variable, allowing indirect access and modification of data.
02 What is the use of the & operator?
The address-of operator & gives the memory address of a variable. Example: &x returns the address where x is stored.
03 What is new and delete?
new dynamically allocates memory on the heap at runtime. delete releases that memory. Always pair them to avoid memory leaks.
04 How are arrays related to pointers?
An array name acts like a pointer to its first element. You can use pointer arithmetic to traverse all array elements.
05 What is a pointer to an object?
A pointer that stores the address of an object. Members are accessed using the arrow operator -> 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.

C++ Advanced OOP Concepts

Virtual Functions & More

Explore runtime polymorphism, friend functions, static functions, the this pointer, and dynamic type information — all explained with clear examples.

TOPIC 01

Virtual Functions

Runtime polymorphism — correct function chosen by object type, not pointer type.

TOPIC 02

Friend Functions

Non-member functions granted special access to private class data.

TOPIC 03

Static Functions

Class-level functions shared across all objects, callable without an instance.

TOPIC 04

This Pointer

Special pointer that always refers to the current object inside a member function.

TOPIC 05

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 functions give flexibility and correct behavior when working with inheritance. Without virtual, the base class version is always called through a base pointer — even if the object is derived.
Without virtual
Base* b = &d;
b->show();
// Always calls Base::show() ⚠️
▶ Output
Base class show function
With virtual
virtual void show() { ... }
// in Base class

Base* b = &d;
b->show();
// Calls Derived::show() ✅
▶ Output
Derived class show function
Program Example
virtual_func.cpp C++
#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
}
▶ Output
Derived class show function
🤝

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.

⚠️ A friend function is not a member of the class. It is declared inside the class with the friend keyword but defined outside — just like a regular function.
friend_func.cpp C++
#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);
}
▶ Output
Value of x: 10
📌

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.

Normal Function
Demo obj;
obj.show();
// requires an object ⚠️
Static Function
Demo::show();
// no object needed ✅
static_func.cpp C++
#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
}
▶ Output
Static function called
✅ Static functions are useful for utility operations that don't depend on any specific object's state.
📋

Assignment and Copy Initialization

Assignment Initialization

Assignment means giving a value to a variable after it is already created.

assignment.cpp C++
int a;     // variable created
a = 10;    // value assigned later
Copy Initialization

Copy initialization means initializing a variable using another variable or value at the time of declaration.

copy_init.cpp C++
int a = 10;   // value given at declaration
int b = a;    // b initialized by copying a
Assignment
int a;
a = 10;
// Value given AFTER creation
Copy Initialization
int a = 10;
int b = a;
// Value given AT declaration
💡 Both look similar, but they work differently internally — especially in classes where copy constructors and assignment operators are involved.
🔦

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 namethis-> 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.
this_pointer.cpp C++
#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();
}
▶ Output
Value of x: 50
🔍

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.
dynamic_type.cpp C++
#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
}
▶ Output (may vary by compiler)
Derived
👉 It tells the actual object type at runtime — even when accessed through a base class pointer.

Frequently Asked Questions

01 What is a virtual function?
A function declared with the virtual keyword that is resolved at runtime based on the actual object type, enabling runtime polymorphism.
02 What is a friend function?
A non-member function that is granted special permission to access the private and protected members of a class using the friend keyword.
03 What is a static function?
A function that belongs to the class itself, not to any specific object. It is called using the class name and can only access static data members.
04 What is the this pointer?
A special implicit pointer available inside every non-static member function that points to the current object, useful for resolving name conflicts between members and parameters.
05 What is dynamic type information?
The ability to identify the actual type of an object at runtime using the 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.