Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A protected member variable in C++ is a class attribute declared under the protected access specifier, restricting direct access to the defining class, its friend functions or classes, and derived classes. It enforces encapsulation from the global scope while extending visibility strictly down the inheritance hierarchy.
class SimpleBase {
protected:
    int protectedData;
};

Access Control Mechanics

The C++ compiler enforces strict rules regarding the compile-time visibility and accessibility of protected names:
  1. Defining Class: Member functions and friends of the defining class have unrestricted access to the variable’s name.
  2. External Scope: Any attempt to access the name from outside the class hierarchy (e.g., from main() or unrelated classes) results in a compilation error, identical to private members.
  3. Derived Classes (Non-Static Members): A derived class can access non-static protected members inherited from its base class, but only through instances of the derived class itself (or further derived classes). A derived class cannot access non-static protected members through a base class instance.
  4. Derived Classes (Static Members): Derived classes can freely access static protected members of a base class. Because the [class.protected] restriction explicitly applies only to non-static members, a derived class can access a protected static member directly, using the base class scope (e.g., StateBase::staticData), or even through a base class instance (e.g., baseInstance.staticData).
class StateBase {
protected:
    int instanceData;
    static int staticData;
};

int StateBase::staticData = 0;

class StateDerived : public StateBase {
public:
    void mutate(StateBase& baseInstance, StateDerived& derivedInstance) {
        this->instanceData = 1;             // Valid: Accessing own inherited member
        derivedInstance.instanceData = 2;   // Valid: Accessing member of the same derived type
        
        // baseInstance.instanceData = 3;   // ERROR: Cannot access non-static protected member of a base instance
        
        staticData = 4;                     // Valid: Accessing static protected member directly
        StateBase::staticData = 5;          // Valid: Accessing static protected member via base class scope
        baseInstance.staticData = 6;        // Valid: Accessing static protected member via base class instance
    }
};

int main() {
    StateDerived obj;
    // obj.instanceData = 7;                // ERROR: Inaccessible from external scope
    return 0;
}

Inheritance Propagation

When a class inherits from a base class containing protected members, the access specifier used for inheritance dictates how the protected member is exposed in the derived class:
  • public Inheritance (class Derived : public Base): The member remains protected in the derived class. It can be accessed by further derived classes.
  • protected Inheritance (class Derived : protected Base): The member remains protected in the derived class. Public members of the base class also become protected in the derived class.
  • private Inheritance (class Derived : private Base): The member becomes private in the derived class. It is accessible within the immediate derived class, but hidden from any subsequent classes that inherit from it.

Access Modification via using Declarations

A derived class can explicitly alter the access level of an inherited protected member by employing a using declaration. This mechanism allows a derived class to expose a protected base member to a broader scope, such as elevating it to public:
class ExposedDerived : public StateBase {
public:
    using StateBase::instanceData; // Elevates access level to public in ExposedDerived
};

Memory Layout Implications

The protected keyword is strictly a compile-time access control mechanism and does not alter the runtime memory footprint of the variable itself. Historically (from C++98 through C++20), the standard specified that the relative allocation order of non-static data members separated by different access control blocks was unspecified, theoretically permitting compiler reordering. However, C++23 changed this rule (via proposal P1847R4). The C++ standard now strictly mandates that all non-static data members are allocated in memory in their exact order of declaration, regardless of any intervening access specifiers. Compilers are no longer permitted to reorder members across distinct access blocks, ensuring a deterministic memory layout.
Master C++ with Deep Grasping Methodology!Learn More