Inheritance Samples
1. Virtual Base Classes / Diamond Problem​
Virtual Inheritance: Solves the diamond problem by ensuring a single instance of the base class.
class B {
public:
    int i;
    B() { i = 10; }
};
class D1: virtual public B { };
class D2: virtual public B { };
class C: public D1, public D2 { };
void main() {
    C obj;
    cout << obj.i; // Without virtual, this would be ambiguous
}
Diamond Problem Diagram:
Explanation:
- Without virtual inheritance, class C would inherit two copies of B (one through D1 and one through D2)
 - This would make obj.i ambiguous - which copy of B's i should it refer to?
 - Using virtual inheritance ensures only one copy of B exists in C
 - This resolves the ambiguity, allowing direct access to i through C objects
 
Output: 10
2. Virtual Destructors​
Virtual Destructors: Ensures proper calling order for destructors in class hierarchies. Essential when deleting derived objects through base class pointers to ensure proper cleanup.
class B {
public:
    virtual ~B() { cout << "destructor B" << endl; }
};
class D: public B {
public:
    int *p;
    D() {
        p = new int;
        *p = 10;
    }
    ~D() {
        cout << "destructor D" << endl;
        delete p;
    }
};
void main() {
    int z;
    B *pobjB;
    D *pobjD = new D();
    pobjB = pobjD;
    delete pobjB;
    cin >> z;
}
Virtual Destructor Diagram:
Explanation:
- When a derived class object is deleted through a base class pointer, the base class destructor must be virtual
 - Without virtual, only the base class destructor would be called, causing a memory leak (p would not be deleted)
 - With virtual, the correct derived class destructor is called first, then the base class destructor
 - This ensures proper cleanup of resources allocated by the derived class
 
Output:
destructor D
destructor B
3. Base-class Access Control​
Access Control: Public, private, and protected members have different visibility in derived classes.
class Base {
public:
    int m_i;
    Base() {
        m_i = 0;
        m_j = 1;
        m_k = 2;
    }
private:
    int m_j;
protected:
    int m_k;
};
class D1: public Base { };
void main() {
    D1 obj;
    cout << obj.m_i;  // Accessible
    //cout << obj.m_j; // Not accessible - private in Base
    //cout << obj.m_k; // Not accessible - protected in Base
}
Access Control Diagram:
Explanation:
- public members (m_i) are accessible from anywhere
 - private members (m_j) are only accessible within the Base class
 - protected members (m_k) are accessible within Base and derived classes, but not from outside
 
Output: 0
4. Constructors and Destructors Execution Order​
- Constructors execute from base to derived
 - Destructors execute from derived to base
 
class B {
public:
    B() { cout << "constructor B" << endl; }
    ~B() { cout << "Destructor B" << endl; }
};
class D1: public B {
public:
    D1() { cout << "constructor D1" << endl; }
    ~D1() { cout << "Destructor D1" << endl; }
};
class D2: public D1 {
public:
    D2() { cout << "constructor D2" << endl; }
    ~D2() { cout << "Destructor D2" << endl; }
};
void main() {
    D2 obj;
}
Constructor/Destructor Order Diagram:
Explanation:
Constructors are called from base to derived (B → D1 → D2) Destructors are called in reverse order, from derived to base (D2 → D1 → B)
Output:
constructor B
constructor D1
constructor D2
Destructor D2
Destructor D1
Destructor B
5. Granting Access​
We can change the access level of inherited members.
class B {
public:
    int i; // public in base
    B() { i = 10; }
};
// Inherit base as private
class D: private B {
public:
    // here is access declaration
    B::i; // make i public again
};
void main() {
    D obj;
    cout << obj.i;
    int z;
    cin >> z;
}
Access Declaration Diagram:
Explanation:
- When inheriting privately, all public members of the base class become private in the derived class
 - The access declaration B::i; in the public section of D makes i public again
 - This allows direct access to i through D objects
 
Output: 10
6. Passing Parameters to Base-class Constructors​
Use initializer lists to pass parameters to base class constructors.
class B {
    int m;
protected:
    int i;
public:
    B(int x) {
        i = x;
        cout << "Constructing base : B\n";
    }
    ~B() {
        cout << "Destructing base : B\n";
    }
};
class D: public B {
    int j;
public:
    // derived uses x; y is passed along to base
    D(int x, int y): B(y) {
        j = x;
        cout << "Constructing derived : D\n";
    }
    ~D() {
        cout << "Destructing derived : D\n";
    }
    void show() {
        cout << i << " " << j << "\n";
    }
};
int main() {
    D obj(1, 2);
    obj.show(); // displays 2 1
    return 0;
}
Constructor Parameter Passing Diagram:
Explanation:
The derived class constructor uses an initializer list (D(int x, int y): B(y)) to pass parameters to the base class constructor The parameter y is passed to the base class constructor, while x is used in the derived class In the show() method, i (from base) is 2 and j (from derived) is 1
Output:
Constructing base : B
Constructing derived : D
2 1
Destructing derived : D
Destructing base : B