public, protected, and private inheritance in C++


Introduction

In C++ inheritance, the way in which members of a base class are accessed in the derived class depends on the access specifier used during inheritance. The three main types of inheritance based on access control are public inheritance, protected inheritance, and private inheritance. Each type affects the visibility of the inherited members (attributes and methods) from the base class in the derived class.

Understanding the differences between these types of inheritance is essential for designing robust object-oriented programs.


1. Public Inheritance

Public inheritance is the most common and widely used form of inheritance in C++. In this type of 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.
  • Private members of the base class are not accessible directly in the derived class.

Public inheritance models an "is-a" relationship. For example, if class Dog is derived from class Animal, then a Dog is a type of Animal.

Syntax for Public Inheritance

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

Example of Public Inheritance:

#include <iostream>
using namespace std;

class Animal {
public:
    void eat() {
        cout << "Animal eats!" << endl;
    }
protected:
    void sleep() {
        cout << "Animal sleeps!" << endl;
    }
private:
    void breathe() {
        cout << "Animal breathes!" << endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        cout << "Dog barks!" << endl;
    }
    void showSleep() {
        sleep();  // Can access protected member of base class
    }
};

int main() {
    Dog dog;
    dog.eat();     // Public member inherited from Animal
    dog.bark();    // Method of Dog class
    dog.showSleep(); // Accessing protected member via a public method

    // dog.breathe(); // Error: Cannot access private member from base class

    return 0;
}

Explanation:

  • The Dog class inherits from Animal using public inheritance.
  • The public method eat() is inherited as public in the Dog class.
  • The protected method sleep() is inherited as protected, so it can be accessed within the Dog class.
  • The private method breathe() is not accessible from the Dog class because it is private in the base class.

2. Protected Inheritance

Protected inheritance is used less frequently than public inheritance. In this form:

  • Public members of the base class become protected in the derived class.
  • Protected members remain protected in the derived class.
  • Private members of the base class are still not accessible in the derived class.

This type of inheritance is useful when you want the derived class to be able to access base class members, but you don’t want those members to be accessible from outside the class hierarchy. It’s often used when you need to control access more tightly within the class hierarchy but still allow subclass members to access base class members.

Syntax for Protected Inheritance

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

Example of Protected Inheritance:

#include <iostream>
using namespace std;

class Animal {
public:
    void eat() {
        cout << "Animal eats!" << endl;
    }
protected:
    void sleep() {
        cout << "Animal sleeps!" << endl;
    }
private:
    void breathe() {
        cout << "Animal breathes!" << endl;
    }
};

class Dog : protected Animal {
public:
    void bark() {
        cout << "Dog barks!" << endl;
    }
    void showSleep() {
        sleep();  // Can access protected member of base class
    }
};

int main() {
    Dog dog;
    dog.eat();     // Error: Cannot access public method as it is protected now
    dog.bark();    // Method of Dog class
    dog.showSleep(); // Accessing protected member via a public method

    // dog.breathe(); // Error: Cannot access private member from base class

    return 0;
}

Explanation:

  • The Dog class inherits from Animal using protected inheritance.
  • The public method eat() is inherited as protected, so it cannot be accessed outside the Dog class (i.e., in main).
  • The protected method sleep() remains protected and is accessible within the derived class.
  • The private method breathe() is still inaccessible to the derived class.

3. Private Inheritance

Private inheritance is the least common and the most restrictive form of inheritance. In this form:

  • Public members of the base class become private in the derived class.
  • Protected members also become private in the derived class.
  • Private members of the base class remain unaccessible.

Private inheritance is used when a class does not want its public interface to be accessible to external code but still needs to inherit behavior or functionality from the base class. This type of inheritance models a has-a or implemented-in-terms-of relationship rather than an "is-a" relationship.

Syntax for Private Inheritance

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

Example of Private Inheritance:

#include <iostream>
using namespace std;

class Animal {
public:
    void eat() {
        cout << "Animal eats!" << endl;
    }
protected:
    void sleep() {
        cout << "Animal sleeps!" << endl;
    }
private:
    void breathe() {
        cout << "Animal breathes!" << endl;
    }
};

class Dog : private Animal {
public:
    void bark() {
        cout << "Dog barks!" << endl;
    }
    void showSleep() {
        sleep();  // Can access protected member of base class
    }
};

int main() {
    Dog dog;
    dog.bark();    // Method of Dog class
    dog.showSleep(); // Accessing protected member via a public method

    // dog.eat();    // Error: Cannot access public member as it is private now
    // dog.breathe(); // Error: Cannot access private member from base class

    return 0;
}

Explanation:

  • The Dog class inherits from Animal using private inheritance.
  • The public method eat() is inherited as private, meaning it cannot be accessed outside the Dog class.
  • The protected method sleep() is inherited as private, making it accessible only within the Dog class.
  • The private method breathe() is not accessible in the Dog class.

4. When to Use Public, Protected, and Private Inheritance

  • Public Inheritance: Use when the derived class is a type of the base class (i.e., an is-a relationship). This is the most common type of inheritance and should be used unless you have a specific need to restrict access to base class members.

  • Protected Inheritance: Use when you want to control access to base class members but still allow derived classes to use them. This is less common but is useful when you want to restrict access from outside the class hierarchy while still allowing derived classes to access base class features.

  • Private Inheritance: Use when the derived class has-a relationship with the base class rather than is-a. This means the derived class is implementing functionality using the base class but does not wish to expose the base class’s functionality to outside users. This type is often used to embed functionality.