How Protected Inheritance Affects Member Visibility in C++

In the C++ programming language, inheritance models not only relationships between classes but also dictates how encapsulation boundaries are preserved. When a class derives from a base class using protected inheritance (class Derived : protected Base), it fundamentally shifts the visibility of inherited members to both outside consumers and subsequent subclasses. Specifically, protected inheritance promotes encapsulation by downgrading public base members to protected status within the derived class, leaving protected members protected, and keeping private members completely inaccessible.

The Core Visibility Transformation Rules

The access specifier used during inheritance acts as a filter that restricts member visibility; it can only reduce accessibility, never increase it. Under protected inheritance, the access levels of the base class members map to the derived class as follows:

  • Public members become protected: Any public member of the base class is treated as protected within the derived class. It remains accessible to member functions and friends of the derived class, as well as to further derived classes, but it is completely inaccessible to external callers using an instance of the derived class.
  • Protected members remain protected: Base class members that were originally protected maintain their protected status. They continue to be accessible within the derived class and any downstream classes inheriting from it, but remain hidden from the global scope.
  • Private members remain inaccessible: Private members of the base class are inherited, but they cannot be accessed directly by the derived class under any inheritance model. They can only be interacted with via inherited public or protected accessors (which themselves become protected).

Impact on External Code and Type Conversion

The primary consequence of protected inheritance occurs outside the class hierarchy. When public members are converted into protected members, the derived class breaks the standard "is-a" relationship commonly associated with public inheritance.

External code interacting with an instance of the derived class cannot invoke any methods that were public in the base class unless the derived class explicitly exposes them (such as via a using declaration). Furthermore, implicit upcasting is restricted. Outside the class hierarchy, a pointer or reference to the derived type cannot be implicitly converted to a pointer or reference to the base type. The compiler enforces this restriction because treating the derived object as a base object from the outside would circumvent the protected access boundary.

Impact on Further Derived Classes

Unlike private inheritance—which converts all accessible base members into private members and prevents subsequent generations from accessing them—protected inheritance maintains the chain of inheritance for subclasses.

If a third class inherits from the derived class (e.g., class GrandChild : public Derived), it can still access all the members that were originally public or protected in the root base class. Within GrandChild, these members remain protected. Additionally, member functions and friends of both Derived and GrandChild retain the ability to implicitly cast pointers or references of their type to the root base class type, preserving implementation reuse across a restricted inheritance tree.