Member Access Control (C++)

Access controls enable you to separate the public interface of a class from the private implementation details and the protected members that are only for use by derived classes. The access specifier applies to all members declared after it until the next access specifier is encountered.

class Point
{
public:
    Point( int, int ) // Declare public constructor.;
    Point();// Declare public default constructor.
    int &x( int ); // Declare public accessor.
    int &y( int ); // Declare public accessor.

private:                 // Declare private state variables.
    int _x;
    int _y;

protected:      // Declare protected function for derived classes only.
    Point ToWindowCoords();
};

The default access is private in a class, and public in a struct or union. Access specifiers in a class can be used any number of times in any order. The allocation of storage for objects of class types is implementation-dependent. However, compilers must guarantee assignment of members to successively higher memory addresses between access specifiers.

Member-Access Control

Type of Access Meaning
private Class members declared as private can be used only by member functions and friends (classes or functions) of the class.
protected Class members declared as protected can be used by member functions and friends (classes or functions) of the class. Additionally, they can be used by classes derived from the class.
public Class members declared as public can be used by any function.

Access control helps prevent you from using objects in ways they weren't intended to be used. This protection is lost when you make explicit type conversions (casts).

Note

Access control is equally applicable to all names: member functions, member data, nested classes, and enumerators.

Access Control in Derived Classes

Two factors control which members of a base class are accessible in a derived class; these same factors control access to the inherited members in the derived class:

  • Whether the derived class declares the base class using the public access specifier.

  • What the access to the member is in the base class.

The following table shows the interaction between these factors and how to determine base-class member access.

Member Access in Base Class

private protected public
Always inaccessible with any derivation access private in derived class if you use private derivation private in derived class if you use private derivation
protected in derived class if you use protected derivation protected in derived class if you use protected derivation
protected in derived class if you use public derivation public in derived class if you use public derivation

The following example illustrates access derivation:

// access_specifiers_for_base_classes.cpp
class BaseClass
{
public:
    int PublicFunc(); // Declare a public member.
protected:
    int ProtectedFunc(); // Declare a protected member.
private:
    int PrivateFunc(); // Declare a private member.
};

// Declare two classes derived from BaseClass.
class DerivedClass1 : public BaseClass
{
    void foo()
    {
        PublicFunc();
        ProtectedFunc();
        PrivateFunc(); // function is inaccessible
    }
};

class DerivedClass2 : private BaseClass
{
    void foo()
    {
        PublicFunc();
        ProtectedFunc();
        PrivateFunc(); // function is inaccessible
    }
};

int main()
{
    DerivedClass1 derived_class1;
    DerivedClass2 derived_class2;
    derived_class1.PublicFunc();
    derived_class2.PublicFunc(); // function is inaccessible
}

In DerivedClass1, the member function PublicFunc is a public member and ProtectedFunc is a protected member because BaseClass is a public base class. PrivateFunc is private to BaseClass, and it's inaccessible to any derived classes.

In DerivedClass2, the functions PublicFunc and ProtectedFunc are considered private members because BaseClass is a private base class. Again, PrivateFunc is private to BaseClass, and it's inaccessible to any derived classes.

You can declare a derived class without a base-class access specifier. In such a case, the derivation is considered private if the derived class declaration uses the class keyword. The derivation is considered public if the derived class declaration uses the struct keyword. For example, the following code:

class Derived : Base
...

is equivalent to:

class Derived : private Base
...

Similarly, the following code:

struct Derived : Base
...

is equivalent to:

struct Derived : public Base
...

Members declared as having private access aren't accessible to functions or derived classes unless those functions or classes are declared using the friend declaration in the base class.

A union type can't have a base class.

Note

When specifying a private base class, it is advisable to explicitly use the private keyword so users of the derived class understand the member access.

Access control and static members

When you specify a base class as private, it affects only nonstatic members. Public static members are still accessible in the derived classes. However, accessing members of the base class using pointers, references, or objects can require a conversion, which applies access control again. Consider the following example:

// access_control.cpp
class Base
{
public:
    int Print();             // Nonstatic member.
    static int CountOf();    // Static member.
};

// Derived1 declares Base as a private base class.
class Derived1 : private Base
{
};

// Derived2 declares Derived1 as a public base class.
class Derived2 : public Derived1
{
    int ShowCount();    // Nonstatic member.
};

// Define ShowCount function for Derived2.
int Derived2::ShowCount()
{
    // Call static member function CountOf explicitly.
    int cCount = ::Base::CountOf();     // OK.

    // Call static member function CountOf using pointer.
    cCount = this->CountOf();  // C2247: 'Base::CountOf'
                               // not accessible because
                               // 'Derived1' uses 'private'
                               // to inherit from 'Base'
    return cCount;
}

In the preceding code, access control prohibits conversion from a pointer to Derived2 to a pointer to Base. The this pointer is implicitly of type Derived2 *. To select the CountOf function, this must be converted to type Base *. Such a conversion isn't permitted because Base is a private indirect base class to Derived2. Conversion to a private base class type is acceptable only for pointers to immediate derived classes. That's why pointers of type Derived1 * can be converted to type Base *.

An explicit call to the CountOf function, without using a pointer, reference, or object to select it, implies no conversion. That's why the call is allowed.

Members and friends of a derived class, T, can convert a pointer to T to a pointer to a private direct base class of T.

Access to virtual functions

The access control applied to virtual functions is determined by the type used to make the function call. Overriding declarations of the function don't affect the access control for a given type. For example:

// access_to_virtual_functions.cpp
class VFuncBase
{
public:
    virtual int GetState() { return _state; }
protected:
    int _state;
};

class VFuncDerived : public VFuncBase
{
private:
    int GetState() { return _state; }
};

int main()
{
   VFuncDerived vfd;             // Object of derived type.
   VFuncBase *pvfb = &vfd;       // Pointer to base type.
   VFuncDerived *pvfd = &vfd;    // Pointer to derived type.
   int State;

   State = pvfb->GetState();     // GetState is public.
   State = pvfd->GetState();     // C2248 error expected; GetState is private;
}

In the preceding example, calling the virtual function GetState using a pointer to type VFuncBase calls VFuncDerived::GetState, and GetState is treated as public. However, calling GetState using a pointer to type VFuncDerived is an access-control violation because GetState is declared private in class VFuncDerived.

Caution

The virtual function GetState can be called using a pointer to the base class VFuncBase. This doesn't mean that the function called is the base-class version of that function.

Access control with multiple inheritance

In multiple-inheritance lattices involving virtual base classes, a given name can be reached through more than one path. Because different access control can be applied along these different paths, the compiler chooses the path that gives the most access. See the following figure:

Diagram showing access along the paths of an inheritance graph.

The diagram shows the following inheritance hierarchy: class VBase is the base class. Class LeftPath inherits from VBase using virtual private VBase. class RightPath also inherits from VBase but using virtual public VBase. Finally, class Derived inherits from both class LeftPath and class RightPath using public LeftPath, public RightPath.

Access along paths of an inheritance graph

In the figure, a name declared in class VBase is always reached through class RightPath. The right path is more accessible because RightPath declares VBase as a public base class, while LeftPath declares VBase as private.

See also

C++ Language Reference