Page Content

Tutorials

What Is Mean By Access Control In Inheritance C++ With Code?

Access Control in Inheritance C++

The visibility and accessibility of base class members both inside a derived class and from external code are determined by access control in inheritance in C++. Data abstraction and encapsulation are key components of object-oriented programming, where classes conceal from users the specifics of their implementation. Code reuse and the modelling of “is-a” relationships (such as an mp3_file “is-a” os_file) are made possible by inheritance.

Fundamental Access Specifiers in C++ Classes

Public: Declared public members can be accessed from any location within the application, including through derived classes and external code. They specify the interface of the class.

Private: Only other classmates (and friends) can access members who have been designated private. By concealing implementation specifics, they uphold encapsulation.

Protected: Members that have been designated as protected can be accessed by friends and methods in their own class as well as by friends and methods of any derived class; but, external code (typical class users) cannot access them. For inheritance hierarchies in particular, this offers a balance between private and public access.

The base class or classes and their optional access specifier (public, protected, or private) are specified in a class derivation list when defining a derived class. This specifier controls how members of the base class are made accessible in the derived class.

Public Inheritance

The most prevalent type of inheritance is public inheritance, which creates a “is-a” relationship.

The public derivation of a class from a base class:

  • The derived class’s public members are those of the base class.
  • Protected members in the base class also become protected in the derived class.
  • The derived class cannot access private members of the base class, which remain private to the base class. Only protected or public base class methods can access them.

Accessibility

  • From derived class members: Members of the protected and public base classes are reachable. Members of the private sector are not.
  • From objects of the derived class (external code): Access is restricted to public members only, including those inherited from the base class.

Code Example for Public Inheritance:

#include <iostream>
class Base {
private:
    int priv_data; // Private to Base
protected:
    int prot_data; // Accessible by derived classes
public:
    int pub_data;  // Accessible by everyone
    Base(int p, int pr, int pu) : priv_data(p), prot_data(pr), pub_data(pu) {}
    void display_base() const {
        std::cout << "Base: priv=" << priv_data << ", prot=" << prot_data << ", pub=" << pub_data << std::endl;
    }
    int get_priv_data() const { return priv_data; } // Accessor for private data 
};
class PublicDerived : public Base {
public:
    PublicDerived(int p, int pr, int pu) : Base(p, pr, pu) {}
    void access_base_members() {
        // std::cout << "Derived trying to access Base's private_data: " << priv_data << std::endl; // Error: inaccessible
        std::cout << "Derived accessing Base's protected_data: " << prot_data << std::endl; // OK 
        std::cout << "Derived accessing Base's public_data: " << pub_data << std::endl;   // OK 
        std::cout << "Derived accessing Base's private_data via accessor: " << get_priv_data() << std::endl; // OK (indirect access) 
    }
};
int main() {
    PublicDerived d(10, 20, 30);
    d.display_base(); // OK: public member of Base, public in PublicDerived
    d.access_base_members(); // OK: public member of PublicDerived
    // std::cout << d.prot_data << std::endl; // Error: protected in Base, protected in PublicDerived, so not accessible externally 
    std::cout << "Accessing PublicDerived's inherited public_data: " << d.pub_data << std::endl; // OK 
    return 0;
}

Output

Base: priv=10, prot=20, pub=30
Derived accessing Base's protected_data: 20
Derived accessing Base's public_data: 30
Derived accessing Base's private_data via accessor: 10
Accessing PublicDerived's inherited public_data: 30

Protected Inheritance

A limited “is-a” connection is defined by protected inheritance, mostly for use in subsequent derivations.

When protected inheritance is used to derive a class:

  • The derived class’s protected members are public members of the base class.
  • Protected members in the base class also become protected in the derived class.
  • Base class private members stay private and unavailable.

Accessibility

  • From derived class members: Members of the derived class can access both public and protected base class members, which are now all protected in the derived class.
  • From further derived classes: Members inherited from the intermediate protected-derived class are available (as protected) from subsequent derived classes.
  • From objects of the derived class (external code): Since they are now protected within the derived class, none of the inherited base class members public or protected can be accessed from objects of the derived class (external code).

Code Example for Protected Inheritance:

#include <iostream>
class Base {
private:
    int priv_data_base;
protected:
    int prot_data_base;
public:
    int pub_data_base;
    Base(int p, int pr, int pu) : priv_data_base(p), prot_data_base(pr), pub_data_base(pu) {}
    void display_base() const {
        std::cout << "Base: priv=" << priv_data_base << ", prot=" << prot_data_base << ", pub=" << pub_data_base << std::endl;
    }
    int get_priv_data_base() const { return priv_data_base; }
};
class ProtectedDerived : protected Base { // Protected inheritance
public:
    ProtectedDerived(int p, int pr, int pu) : Base(p, pr, pu) {}
    void access_base_members_protected() {
        // std::cout << "Derived trying to access Base's private_data_base: " << priv_data_base << std::endl; // Error: inaccessible
        std::cout << "Derived accessing Base's protected_data_base (now protected): " << prot_data_base << std::endl; // OK
        std::cout << "Derived accessing Base's public_data_base (now protected): " << pub_data_base << std::endl; // OK
        std::cout << "Derived accessing Base's private_data_base via accessor: " << get_priv_data_base() << std::endl; // OK (indirect access)
    }
    // void display_base() const { Base::display_base(); } // Cannot make it public here.
};
class FurtherDerivedFromProtected : public ProtectedDerived { // Deriving from ProtectedDerived
public:
    FurtherDerivedFromProtected(int p, int pr, int pu) : ProtectedDerived(p, pr, pu) {}
    void access_inherited_members() {
        // std::cout << "Further derived trying to access Base's private_data_base: " << priv_data_base << std::endl; // Error: inaccessible
        std::cout << "Further derived accessing Base's prot_data_base (inherited as protected): " << prot_data_base << std::endl; // OK
        std::cout << "Further derived accessing Base's pub_data_base (inherited as protected): " << pub_data_base << std::endl; // OK
    }
};
int main() {
    ProtectedDerived pd(100, 200, 300);
    // pd.display_base(); // Error: display_base is protected in ProtectedDerived
    // std::cout << pd.pub_data_base << std::endl; // Error: pub_data_base is protected in ProtectedDerived
    FurtherDerivedFromProtected fdp(1, 2, 3);
    fdp.access_inherited_members(); // OK
    // fdp.display_base(); // Still not accessible via fdp object, as it's protected from ProtectedDerived
    return 0;
}

Output

Further derived accessing Base's prot_data_base (inherited as protected): 2
Further derived accessing Base's pub_data_base (inherited as protected): 3

Private Inheritance

When a derived class wants to utilize a base class’s functionality but does not want its functionality to be accessible to other classes or external code, private inheritance is employed. Functionality is utilized internally but is not publicly visible, much like composition.

When private inheritance is used to derive a class:

  • Private members of the derived class are created from public members of the base class.
  • Private members of the derived class are created from protected members of the base class.
  • Base class private members stay private and unavailable.

Accessibility

  • From derived class members: Members of the derived class can access both public and protected base class members (all of whom are now private in the derived class).
  • From further derived classes: Since they are now private within the derived class, none of the inherited base class members public, protected, or private are available.
  • From objects of the derived class (external code): Since they are now private within the derived class, none of the members of the inherited base class are available.

Code Example for Private Inheritance:

#include <iostream>
class Base {
private:
    int priv_data_base;
protected:
    int prot_data_base;
public:
    int pub_data_base;
    Base(int p, int pr, int pu) : priv_data_base(p), prot_data_base(pr), pub_data_base(pu) {}
    void display_base() const {
        std::cout << "Base: priv=" << priv_data_base << ", prot=" << prot_data_base << ", pub=" << pub_data_base << std::endl;
    }
    int get_priv_data_base() const { return priv_data_base; }
};
class PrivateDerived : private Base { // Private inheritance
public:
    PrivateDerived(int p, int pr, int pu) : Base(p, pr, pu) {}
    void access_base_members_private() {
        // std::cout << "Derived trying to access Base's private_data_base: " << priv_data_base << std::endl; // Error: inaccessible
        std::cout << "Derived accessing Base's protected_data_base (now private): " << prot_data_base << std::endl; // OK
        std::cout << "Derived accessing Base's public_data_base (now private): " << pub_data_base << std::endl; // OK
        std::cout << "Derived accessing Base's private_data_base via accessor: " << get_priv_data_base() << std::endl; // OK (indirect access)
    }
    // void display_base() const { Base::display_base(); } // Cannot be public as Base::display_base is now private
};
class FurtherDerivedFromPrivate : public PrivateDerived { // Deriving from PrivateDerived
public:
    FurtherDerivedFromPrivate(int p, int pr, int pu) : PrivateDerived(p, pr, pu) {}
    void access_inherited_members() {
        // std::cout << "Further derived trying to access Base's prot_data_base: " << prot_data_base << std::endl; // Error: inaccessible
        // std::cout << "Further derived trying to access Base's pub_data_base: " << pub_data_base << std::endl; // Error: inaccessible
    }
};
int main() {
    PrivateDerived pd(1000, 2000, 3000);
    // pd.display_base(); // Error: display_base is private in PrivateDerived
    // std::cout << pd.pub_data_base << std::endl; // Error: pub_data_base is private in PrivateDerived
    pd.access_base_members_private(); // OK
    FurtherDerivedFromPrivate fdp(1, 2, 3);
    fdp.access_inherited_members(); // Members inherited from Base are private in PrivateDerived, so inaccessible here.
    return 0;
}

Output

Derived accessing Base's protected_data_base (now private): 2000
Derived accessing Base's public_data_base (now private): 3000
Derived accessing Base's private_data_base via accessor: 1000

Changing Access Level with Declarations

To modify an individual inherited member’s access level within a derived class, use a using declaration. This is especially helpful for selectively exposing specific members of the base class in cases of private or protected inheritance.


If Base::f is protected, derived
: public Base { public: using Base::f; }; makes derived::f public.

If Base::f is public, derived : public Base { protected: using Base::f; }; makes derived::f protected.

Information that was previously inaccessible (such as making a private base member public) cannot be accessed through a using declaration.

Default Inheritance Access Levels

The keyword used to specify the derived class determines the default inheritance specifier:

  • The derived class’s default inheritance is private if the class keyword is present.
  • The default inheritance is public if the derived class uses the struct keyword.

Instead of depending on defaults to convey the intent, it is best practice to explicitly declare the inherited access specifier.

Summary of Inheritance and Accessibility

Base Class VisibilityPublic InheritanceProtected InheritancePrivate Inheritance
PrivateInaccessibleInaccessibleInaccessible
PublicPublicProtectedPrivate
ProtectedProtectedProtectedPrivate
Agarapu Geetha
Agarapu Geetha
My name is Agarapu Geetha, a B.Com graduate with a strong passion for technology and innovation. I work as a content writer at Govindhtech, where I dedicate myself to exploring and publishing the latest updates in the world of tech.
Index