public, protected, and private inheritance in C++
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.
Public inheritance is the most common and widely used form of inheritance in C++. In this type of inheritance:
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
.
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:
Dog
class inherits from Animal
using public inheritance.eat()
is inherited as public in the Dog
class.sleep()
is inherited as protected, so it can be accessed within the Dog
class.breathe()
is not accessible from the Dog
class because it is private in the base class.Protected inheritance is used less frequently than public inheritance. In this form:
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.
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:
Dog
class inherits from Animal
using protected inheritance.eat()
is inherited as protected, so it cannot be accessed outside the Dog
class (i.e., in main
).sleep()
remains protected and is accessible within the derived class.breathe()
is still inaccessible to the derived class.Private inheritance is the least common and the most restrictive form of inheritance. In this form:
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.
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:
Dog
class inherits from Animal
using private inheritance.eat()
is inherited as private, meaning it cannot be accessed outside the Dog
class.sleep()
is inherited as private, making it accessible only within the Dog
class.breathe()
is not accessible in the Dog
class.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.