⚙️ C++

OOP: C++ में वंशानुक्रम: विस्तृत मार्गदर्शिका

```html

What is it and why? (a real-life analogy)

Imagine you decided to create your own video game. It has different types of vehicles: cars, motorcycles, trucks. Each of them has common features: they can all drive, turn, and honk. But there are also differences: a truck has a cargo bed, a motorcycle has two wheels, and a car has four doors.

If we were to write code for each type of vehicle separately, we would have to rewrite the "drive", "turn", and "honk" functions every time. This is time-consuming, tedious, and error-prone. And what if we notice a bug in the "drive" function for the motorcycle? We would have to fix it in three places at once!

Inheritance is a mechanism that allows you to create one common class (let's call it "Vehicle"), in which we describe all common properties and actions. Then, create derived classes from it: "Car", "Motorcycle", "Truck". They automatically get everything the parent has and can add their own specifics.

💡 Simple analogy: Inheritance is like inheriting a house from your grandmother. You get a ready-made foundation, walls, and roof. You can live in it as is, or you can add an attic or a garage. Similarly, a derived class gets the ready-made fields and methods of the parent and can add its own.

Why is this needed in real development? Imagine you work for a company that makes a banking application. There are different types of accounts: debit, credit, savings. All have an account number, balance, and the ability to deposit and withdraw money. But a credit account has a limit and interest, while a savings account has a deposit rate. Inheritance allows you to write the common logic once in the parent class "Account", and in the derived classes only what distinguishes them.

Theory: how it works internally

Let's look "under the hood" and understand what happens in the computer's memory when we use inheritance.

Base and Derived classes

The class from which others inherit is called the base class (or parent class, or superclass). The class that inherits is called the derived class (or child class, or subclass).

When you create an object of a derived class, memory is first allocated for all fields of the base class, and then for the fields of the derived class. Imagine a Russian nesting doll: first, the largest doll (base class) is placed, and then a smaller one (derived class) is placed inside it.

Access specifiers in inheritance

In C++, there are three ways to inherit: public, protected, and private. They determine how the members of the base class are visible in the derived class.

Inheritance type public members of base protected members of base private members of base
public become public in derived become protected in derived inaccessible (remain private in base)
protected become protected in derived become protected in derived inaccessible
private become private in derived become private in derived inaccessible
⚠️ Important: private members of the base class are never directly accessible in the derived class, even if you inherit publicly. Access to them is only possible through public or protected methods of the base class.

Order of constructor and destructor calls

When an object of a derived class is created, the constructor of the base class is called first, then the constructor of the derived class. Upon destruction, the order is reversed: first the destructor of the derived class, then the base class. This is logical: first the foundation is built, then the walls; when demolishing, the walls are dismantled first, then the foundation.

Method overriding

A derived class can override a method of the base class, i.e., write its own version with the same name and parameters. When you call this method on an object of the derived class, its version is executed, not the parent's. This is called polymorphism (we will discuss it in more detail in the next article).

Syntax in C++: all forms and variants

Let's break down the syntax with specific examples. The basic form looks like this:

class BaseClass {
    // class members
};

class DerivedClass : access_specifier BaseClass {
    // additional members
};

Variant 1: Public inheritance (most common)

class Animal {
public:
    void eat() {
        cout << "Animal is eating" << endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        cout << "Woof!" << endl;
    }
};

Variant 2: Protected inheritance

class Base {
protected:
    int protectedValue;
};

class Derived : protected Base {
    // protectedValue becomes protected in Derived
    // and is accessible inside Derived and its heirs
};

Variant 3: Private inheritance

class Base {
public:
    void publicMethod() {}
};

class Derived : private Base {
    // publicMethod becomes private in Derived
    // accessible only inside Derived
};

Variant 4: Multiple inheritance

C++ allows inheriting from several classes simultaneously:

class Flying {
public:
    void fly() { cout << "Flying" << endl; }
};

class Swimming {
public:
    void swim() { cout << "Swimming" << endl; }
};

class Duck : public Flying, public Swimming {
    // Duck can both fly and swim
};

Examples in code: from simple to complex

Example 1: Basic inheritance (Vehicle)

#include <iostream>
#include <string>
using namespace std;

class Vehicle {
protected:
    string brand;
    int year;
public:
    Vehicle(string b, int y) : brand(b), year(y) {}
    
    void start() {
        cout << brand << " is starting" << endl;
    }
    
    void stop() {
        cout << brand << " is stopping" << endl;
    }
};

class Car : public Vehicle {
private:
    int doorsCount;
public:
    Car(string b, int y, int doors) 
        : Vehicle(b, y), doorsCount(doors) {}
    
    void honk() {
        cout << brand << " honks: Beep-beep!" << endl;
    }
};

int main() {
    Car myCar("Toyota", 2020, 4);
    myCar.start();  // inherited method
    myCar.honk();   // own method
    myCar.stop();   // inherited method
    return 0;
}

Example 2: Method overriding

class Shape {
public:
    virtual void draw() {
        cout << "Drawing a shape" << endl;
    }
};

class Circle : public Shape {
public:
    void draw() override {  // overriding the method
        cout << "Drawing a circle" << endl;
    }
};

class Square : public Shape {
public:
    void draw() override {
        cout << "Drawing a square" << endl;
    }
};

Example 3: Calling the base class constructor

class Employee {
protected:
    string name;
    int id;
public:
    Employee(string n, int i) : name(n), id(i) {
        cout << "Employee constructor: " << name << endl;
    }
};

class Manager : public Employee {
private:
    int teamSize;
public:
    // Calling the base class constructor via initializer list
    Manager(string n, int i, int size) 
        : Employee(n, i), teamSize(size) {
        cout << "Manager constructor: " << name << endl;
    }
};

Common mistakes and pitfalls

Mistake 1: Forgetting to call the base class constructor

If the base class has a parameterized constructor and no default constructor, the derived class must explicitly call it. Otherwise, the compiler will throw an error.

Mistake 2: Slicing

If you pass an object of a derived class to a function that takes a base class by value, only the base part of the object will be copied. This is called slicing.

void processShape(Shape s) {  // taking by value!
    s.draw();  // will always call Shape::draw(), not Circle::draw()
}

Circle c;
processShape(c);  // slicing occurs!

To avoid this, pass by reference or pointer:

void processShape(Shape& s) {  // correct
    s.draw();  // will call the overridden method
}

Mistake 3: Diamond problem in multiple inheritance

If two base classes inherit from the same class, and a derived class inherits from both, ambiguity arises. C++ solves this using virtual inheritance.

class Animal {
public:
    void eat() {}
};

class Mammal : virtual public Animal {};
class Bird : virtual public Animal {};
class Bat : public Mammal, public Bird {};  // only one copy of Animal

Conclusion

Inheritance is a powerful tool that allows you to avoid code duplication and build a hierarchy of classes. It is the foundation of object-oriented programming. However, like any powerful tool, it requires careful handling: remember about slicing, the diamond problem, and the correct order of constructor calls.

In the next article, we will look at polymorphism — the ability of objects to behave differently depending on their type. This is what makes inheritance truly powerful!

```