Introduction to C++ | Access Specifiers
Access Specifiers in Public Inheritance
In C++, access specifiers (public, protected, and private) determine the accessibility of members (variables and methods) in a class. In public inheritance, the way these access specifiers behave in the derived class depends on how they are defined in the base class.
Key Points
- Public inheritance allows a derived class to inherit public and protected members of the base class with the same level of access.
- Private members of the base class are not accessible directly in the derived class, but they can be accessed through public or protected member functions of the base class.
Access Rules in Public Inheritance
Base Class Member | Access in Derived Class |
---|---|
Public | Remains public in the derived class. |
Protected | Remains protected in the derived class. |
Private | Not directly accessible in the derived class. |
Syntax
Public Inheritance Syntax
class Base {
public:
int publicVar;
protected:
int protectedVar;
private:
int privateVar;
};
class Derived : public Base {
public:
void show() {
publicVar = 10; // Accessible (remains public)
protectedVar = 20; // Accessible (remains protected)
// privateVar = 30; // Not accessible (private in Base)
}
};
Example of Public Inheritance
Here is an example to demonstrate the behavior of access specifiers in public inheritance:
Code Example
#include <iostream>
using namespace std;
class Base {
public:
int publicVar;
protected:
int protectedVar;
private:
int privateVar;
public:
Base() : publicVar(1), protectedVar(2), privateVar(3) {}
void displayPrivateVar() {
cout << "Private Variable (accessed within Base): " << privateVar << endl;
}
};
class Derived : public Base {
public:
void accessBaseMembers() {
cout << "Public Variable: " << publicVar << endl;
cout << "Protected Variable: " << protectedVar << endl;
// privateVar is not accessible
}
};
int main() {
Derived obj;
obj.accessBaseMembers();
// Accessing Base class public member through Derived object
obj.publicVar = 42;
cout << "Modified Public Variable: " << obj.publicVar << endl;
// obj.protectedVar = 10; // Error: protected member
// obj.privateVar = 10; // Error: private member
obj.displayPrivateVar(); // Accessing private member through Base class function
return 0;
}
Output
Protected Variable: 2
Modified Public Variable: 42
Private Variable (accessed within Base): 3
Explanation
In this example:
- The publicVar remains public in the derived class, so it can be accessed and modified directly through an object of the derived class.
- The protectedVar remains protected, so it can be accessed within the derived class but not outside it.
- The privateVar is not accessible in the derived class but can be accessed indirectly through a public function of the base class.
Key Takeaways
- In public inheritance, public and protected members of the base class retain their original access levels in the derived class.
- Private members of the base class are not accessible in the derived class, even in public inheritance.
- To control access to private members, provide public or protected member functions in the base class.
Understanding Private Inheritance
In C++, inheritance is a mechanism where a class (child or derived class) acquires properties and behaviors (methods) from another class (parent or base class). With private inheritance, all the public and protected members of the base class become private members of the derived class.
Key Characteristics of Private Inheritance
- Private inheritance is denoted using the
private
keyword in the class declaration. - The derived class cannot directly access the base class's members outside of its own implementation.
- Public and protected members of the base class are inherited as private members of the derived class.
- Private members of the base class remain inaccessible to the derived class.
Syntax
Private Inheritance Syntax
class Base {
public:
int publicVar;
protected:
int protectedVar;
private:
int privateVar;
};
class Derived : private Base {
public:
void show() {
publicVar = 10; // Accessible as private in Derived
protectedVar = 20; // Accessible as private in Derived
// privateVar = 30; // Error: Not accessible
}
};
Example of Private Inheritance
Below is an example demonstrating private inheritance and how access to base class members is affected:
Code Example
#include <iostream>
using namespace std;
class Base {
public:
int publicVar;
Base() : publicVar(0), protectedVar(0), privateVar(0) {}
protected:
int protectedVar;
private:
int privateVar; // Not accessible in the derived class
};
class Derived : private Base {
public:
void accessBaseMembers() {
publicVar = 5; // Inherited as private
protectedVar = 10; // Inherited as private
cout << "PublicVar: " << publicVar << endl;
cout << "ProtectedVar: " << protectedVar << endl;
}
};
int main() {
Derived d;
d.accessBaseMembers();
// d.publicVar = 10; // Error: publicVar is private in Derived
// d.protectedVar = 15; // Error: protectedVar is private in Derived
return 0;
}
Output
ProtectedVar: 10
Effects of Private Inheritance
- The derived class has full control over the base class's public and protected members.
- The base class's public and protected members are hidden from the outside world when accessed through the derived class.
- Private inheritance is useful when the "is-a" relationship is not strictly true, but the derived class wants to reuse the implementation of the base class.
Comparison with Public and Protected Inheritance
Access Level | Public Inheritance | Protected Inheritance | Private Inheritance |
---|---|---|---|
Base Class Public Members | Public in Derived | Protected in Derived | Private in Derived |
Base Class Protected Members | Protected in Derived | Protected in Derived | Private in Derived |
Base Class Private Members | Not Inherited | Not Inherited | Not Inherited |
When to Use Private Inheritance
- When you want to use the implementation of the base class but do not want to expose its interface.
- When the derived class is not conceptually a subtype of the base class (i.e., "is not strictly a" relationship).
- To enforce encapsulation by hiding base class members from external access.
Understanding Protected Inheritance
In C++, inheritance allows a derived class to acquire properties and behaviors of a base class. The type of inheritance (public, protected, or private) determines how the access specifiers (public
, protected
, and private
) of the base class members are treated in the derived class. Here, we focus on protected inheritance.
What is Protected Inheritance?
When a class is derived using protected
inheritance:
- All
public
andprotected
members of the base class become protected members in the derived class. Private
members of the base class are not accessible directly in the derived class, but they can still be accessed through public or protected methods of the base class.
Syntax
Protected Inheritance Syntax
class Base {
// Members of the Base class
};
class Derived : protected Base {
// Members of the Derived class
};
Understanding Access Changes
Base Class Member | Access in Derived Class | Access in Further Derived Class |
---|---|---|
Public | Protected | Protected |
Protected | Protected | Protected |
Private | Not Accessible | Not Accessible |
Example of Protected Inheritance
Here’s an example demonstrating how members of a base class behave under protected inheritance:
Code Example
#include <iostream>
using namespace std;
class Base {
public:
int publicData = 1;
protected:
int protectedData = 2;
private:
int privateData = 3;
public:
int getPrivateData() { return privateData; } // Accessor for private data
};
class Derived : protected Base {
public:
void display() {
cout << "Public data (now protected in Derived): " << publicData << endl;
cout << "Protected data: " << protectedData << endl;
cout << "Private data (via accessor): " << getPrivateData() << endl;
}
};
class FurtherDerived : public Derived {
public:
void show() {
// publicData and protectedData are accessible as protected in this class
cout << "Accessing publicData (protected in Derived): " << publicData << endl;
cout << "Accessing protectedData: " << protectedData << endl;
// getPrivateData() is accessible because it is public in Base
}
};
int main() {
Derived d;
d.display();
FurtherDerived fd;
fd.show();
return 0;
}
Output
Protected data: 2
Private data (via accessor): 3
Accessing publicData (protected in Derived): 1
Accessing protectedData: 2
Key Points to Remember
- Members declared
private
in the base class are not inherited directly by the derived class. - Protected inheritance makes all
public
andprotected
members of the base class protected in the derived class. - Protected inheritance is often used in scenarios where you want to provide restricted access to certain members while still allowing inheritance.
Pro Tip:
💡 Pro Tip
Use public inheritance when the derived class is a specialized version of the base class (i.e., follows the "is-a" relationship). Ensure you carefully manage access to protected and private members to maintain encapsulation.
Private inheritance is rarely used compared to public or protected inheritance. It is suitable for scenarios where you want to hide the "is-a" relationship while reusing the implementation of the base class. Consider using composition as an alternative if the "has-a" relationship fits better.
Use protected inheritance when the derived class represents a specialized version of the base class and access to the base class members should be restricted to the derived class hierarchy only. For example, it can be useful in frameworks and libraries where controlled inheritance is needed.