Inheritance in C++

Understand the concept of inheritance, its types, syntax, and uses in C++.

Inheritance in C++ Interview with follow-up questions

Interview Question Index

Question 1: What is inheritance in C++ and why is it important?

Answer:

Inheritance is a feature in C++ that allows a class to inherit properties and behaviors from another class. The class that inherits is called the derived class or subclass, and the class from which it inherits is called the base class or superclass. Inheritance is important because it promotes code reusability, allows for the creation of more specialized classes, and enables polymorphism.

Back to Top ↑

Follow up 1: Can you explain the different types of inheritance supported in C++?

Answer:

C++ supports several types of inheritance:

  1. Single inheritance: A derived class inherits from a single base class.

  2. Multiple inheritance: A derived class can inherit from multiple base classes.

  3. Multilevel inheritance: A derived class inherits from another derived class, creating a hierarchy of classes.

  4. Hierarchical inheritance: Multiple derived classes inherit from a single base class.

  5. Hybrid inheritance: A combination of multiple inheritance and multilevel inheritance.

Back to Top ↑

Follow up 2: How does inheritance promote code reusability?

Answer:

Inheritance promotes code reusability by allowing the derived class to inherit properties and behaviors from the base class. This means that the derived class does not need to redefine or reimplement those properties and behaviors, saving development time and reducing code duplication. By reusing existing code, developers can build upon and extend the functionality of the base class without having to start from scratch.

Back to Top ↑

Follow up 3: What is the syntax to implement inheritance in C++?

Answer:

The syntax to implement inheritance in C++ is as follows:

// Base class
class BaseClass {
    // Base class members
};

// Derived class
class DerivedClass : public BaseClass {
    // Derived class members
};

In this example, the derived class DerivedClass is inheriting from the base class BaseClass using the public access specifier. The public access specifier indicates that the public members of the base class will be accessible in the derived class.

Back to Top ↑

Follow up 4: Can you provide a real-world example where inheritance can be effectively used?

Answer:

One real-world example where inheritance can be effectively used is in a banking system. The base class could be Account, which contains common properties and methods for all types of accounts, such as accountNumber, balance, and deposit(). The derived classes could be SavingsAccount, CheckingAccount, and LoanAccount, which inherit from the Account class and add specific properties and methods unique to each type of account. This allows for code reusability and the ability to treat different types of accounts as instances of the base class, enabling polymorphism.

Back to Top ↑

Question 2: What is the difference between public, protected, and private inheritance in C++?

Answer:

In C++, public, protected, and private are access specifiers that can be used when inheriting a class.

  • Public inheritance: In public inheritance, all public members of the base class become public members of the derived class, all protected members of the base class become protected members of the derived class, and all private members of the base class remain inaccessible to the derived class.

  • Protected inheritance: In protected inheritance, all public and protected members of the base class become protected members of the derived class, and all private members of the base class remain inaccessible to the derived class.

  • Private inheritance: In private inheritance, all public and protected members of the base class become private members of the derived class, and all private members of the base class remain inaccessible to the derived class.

Back to Top ↑

Follow up 1: Can you provide an example of each?

Answer:

Sure, here are examples of each type of inheritance:

  • Public inheritance: ```cpp class Base { public: void publicMethod() {} protected: void protectedMethod() {} private: void privateMethod() {} };

class Derived : public Base { // publicMethod() is accessible // protectedMethod() is accessible // privateMethod() is not accessible };


- Protected inheritance:
```cpp
class Base {
public:
    void publicMethod() {}
protected:
    void protectedMethod() {}
private:
    void privateMethod() {}
};

class Derived : protected Base {
    // publicMethod() is not accessible
    // protectedMethod() is accessible
    // privateMethod() is not accessible
};
  • Private inheritance: ```cpp class Base { public: void publicMethod() {} protected: void protectedMethod() {} private: void privateMethod() {} };

class Derived : private Base { // publicMethod() is not accessible // protectedMethod() is not accessible // privateMethod() is not accessible };

Back to Top ↑

Follow up 2: How does the access specifier of the base class affect the members of the derived class in each case?

Answer:

The access specifier of the base class affects the accessibility of its members in the derived class as follows:

  • Public inheritance: Public members of the base class remain public in the derived class, protected members of the base class remain protected in the derived class, and private members of the base class remain inaccessible to the derived class.

  • Protected inheritance: Public and protected members of the base class become protected members of the derived class, and private members of the base class remain inaccessible to the derived class.

  • Private inheritance: Public and protected members of the base class become private members of the derived class, and private members of the base class remain inaccessible to the derived class.

Back to Top ↑

Follow up 3: In what scenarios would you use each type of inheritance?

Answer:

The choice of inheritance type depends on the desired relationship between the base class and the derived class:

  • Public inheritance: Use public inheritance when the derived class is a specialized version of the base class and should inherit all its public and protected members.

  • Protected inheritance: Use protected inheritance when the derived class is a specialized version of the base class and should inherit all its protected members, but not its public members.

  • Private inheritance: Use private inheritance when the derived class is a specialized version of the base class and should inherit all its members, but they should be private and not accessible from outside the derived class.

Back to Top ↑

Question 3: What is multiple inheritance in C++ and how is it different from multilevel inheritance?

Answer:

Multiple inheritance is a feature in C++ where a class can inherit from more than one base class. This means that a derived class can have multiple parent classes. On the other hand, multilevel inheritance is a feature in C++ where a class can inherit from another derived class. This means that a derived class can have a parent class, which in turn can have its own parent class. The key difference between multiple inheritance and multilevel inheritance is that multiple inheritance allows a class to inherit from multiple base classes directly, while multilevel inheritance allows a class to inherit from a chain of derived classes.

Back to Top ↑

Follow up 1: Can you provide an example of multiple and multilevel inheritance?

Answer:

Sure! Here's an example of multiple inheritance:

#include 

class Base1 {
public:
    void display1() {
        std::cout << "Base1 Display" << std::endl;
    }
};

class Base2 {
public:
    void display2() {
        std::cout << "Base2 Display" << std::endl;
    }
};

class Derived : public Base1, public Base2 {
public:
    void displayDerived() {
        std::cout << "Derived Display" << std::endl;
    }
};

int main() {
    Derived d;
    d.display1();
    d.display2();
    d.displayDerived();
    return 0;
}

And here's an example of multilevel inheritance:

#include 

class Base {
public:
    void displayBase() {
        std::cout << "Base Display" << std::endl;
    }
};

class Derived : public Base {
public:
    void displayDerived() {
        std::cout << "Derived Display" << std::endl;
    }
};

class Derived2 : public Derived {
public:
    void displayDerived2() {
        std::cout << "Derived2 Display" << std::endl;
    }
};

int main() {
    Derived2 d;
    d.displayBase();
    d.displayDerived();
    d.displayDerived2();
    return 0;
}
Back to Top ↑

Follow up 2: What are the potential problems with multiple inheritance and how can they be avoided?

Answer:

Multiple inheritance can introduce a few potential problems:

  1. Ambiguity: If two or more base classes have a member with the same name, it can lead to ambiguity in the derived class. This can be avoided by using scope resolution operator (::) to specify which base class member to use.

  2. Diamond Problem: If two base classes of a derived class have a common base class, it can lead to the diamond problem. This occurs when the common base class is inherited twice, causing ambiguity. This can be avoided by using virtual inheritance.

  3. Complexity: Multiple inheritance can make the code more complex and harder to understand. It is important to carefully design the class hierarchy and consider alternative approaches if the complexity becomes too high.

Back to Top ↑

Follow up 3: How does C++ resolve the ambiguity in case of multiple inheritance?

Answer:

C++ resolves the ambiguity in case of multiple inheritance by using the scope resolution operator (::) to specify which base class member to use. For example, if two base classes have a member with the same name, you can use the scope resolution operator to access the member of a specific base class.

Here's an example:

#include 

class Base1 {
public:
    void display() {
        std::cout << "Base1 Display" << std::endl;
    }
};

class Base2 {
public:
    void display() {
        std::cout << "Base2 Display" << std::endl;
    }
};

class Derived : public Base1, public Base2 {
public:
    void displayDerived() {
        Base1::display(); // Accessing Base1's display()
        Base2::display(); // Accessing Base2's display()
    }
};

int main() {
    Derived d;
    d.displayDerived();
    return 0;
}

In this example, the displayDerived() function in the Derived class uses the scope resolution operator to access the display() functions of both Base1 and Base2 classes.

Back to Top ↑

Question 4: What is the concept of virtual base class in C++?

Answer:

In C++, a virtual base class is a base class that is declared as virtual in a derived class. When a class is derived from a virtual base class, it ensures that only one instance of the base class is inherited by the derived class, even if the base class is inherited multiple times through different paths in the inheritance hierarchy. This concept is used to avoid the 'diamond problem' that can occur in multiple inheritance.

Back to Top ↑

Follow up 1: Why is it used in the context of multiple inheritance?

Answer:

Virtual base classes are used in the context of multiple inheritance to avoid the 'diamond problem'. The 'diamond problem' occurs when a class is derived from two or more classes that have a common base class. Without using virtual base classes, the derived class would have multiple instances of the common base class, leading to ambiguity and potential conflicts. By using virtual base classes, only one instance of the common base class is inherited, resolving the ambiguity.

Back to Top ↑

Follow up 2: How does it help in resolving ambiguity in multiple inheritance?

Answer:

Virtual base classes help in resolving ambiguity in multiple inheritance by ensuring that only one instance of the base class is inherited, even if it is inherited through different paths in the inheritance hierarchy. This avoids the ambiguity and conflicts that can arise when a derived class has multiple instances of the same base class. By using virtual base classes, the derived class can access the common base class through any of its paths in the inheritance hierarchy without duplication.

Back to Top ↑

Follow up 3: Can you provide an example of the use of virtual base class?

Answer:

Sure! Here's an example:

#include 

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

class Mammal : public virtual Animal {
public:
    void walk() {
        std::cout << "Mammal is walking" << std::endl;
    }
};

class Bird : public virtual Animal {
public:
    void fly() {
        std::cout << "Bird is flying" << std::endl;
    }
};

class Bat : public Mammal, public Bird {
public:
    void sleep() {
        std::cout << "Bat is sleeping" << std::endl;
    }
};

int main() {
    Bat bat;
    bat.eat();
    bat.walk();
    bat.fly();
    bat.sleep();
    return 0;
}

In this example, the classes Mammal and Bird both inherit virtually from the Animal class. This ensures that the Bat class, which inherits from both Mammal and Bird, only has one instance of the Animal class. Without using virtual inheritance, Bat would have two instances of Animal, leading to ambiguity and potential conflicts.

Back to Top ↑

Question 5: What is the role of constructors and destructors in inheritance?

Answer:

Constructors and destructors play an important role in inheritance. When a derived class is created, the constructor of the base class is called first, followed by the constructor of the derived class. This ensures that the base class is properly initialized before the derived class. Similarly, when an object of a derived class is destroyed, the destructor of the derived class is called first, followed by the destructor of the base class. This ensures that the resources allocated by the derived class are properly released before the base class.

Back to Top ↑

Follow up 1: What is the order of execution of constructors and destructors in inheritance?

Answer:

In inheritance, the order of execution of constructors and destructors is as follows:

  1. When a derived class object is created, the constructor of the base class is called first, followed by the constructor of the derived class.
  2. When a derived class object is destroyed, the destructor of the derived class is called first, followed by the destructor of the base class.

This order ensures that the base class is properly initialized before the derived class, and that the resources allocated by the derived class are properly released before the base class.

Back to Top ↑

Follow up 2: How can base class constructors be called from derived class?

Answer:

Base class constructors can be called from the derived class using the constructor initialization list. In the constructor initialization list, the base class constructor is called with the required arguments. Here's an example:

#include 
using namespace std;

class Base {
public:
    Base(int x) {
        cout << "Base constructor called with " << x << endl;
    }
};

class Derived : public Base {
public:
    Derived(int x, int y) : Base(x) {
        cout << "Derived constructor called with " << y << endl;
    }
};

int main() {
    Derived d(10, 20);
    return 0;
}

Output:

Base constructor called with 10
Derived constructor called with 20
Back to Top ↑

Follow up 3: What happens if a base class destructor is not declared virtual?

Answer:

If a base class destructor is not declared virtual and a derived class object is deleted through a pointer to the base class, the behavior is undefined. This is because the derived class destructor will not be called, leading to potential resource leaks or other issues. To ensure proper destruction of derived class objects, it is recommended to declare the base class destructor as virtual. This allows the destructor of the derived class to be called when deleting a derived class object through a pointer to the base class.

Back to Top ↑