Modifying Inherited Member Access

In C++, we have the flexibility to change the access level of an inherited member in a derived class. This is achieved using a using declaration, which identifies the base class member and specifies the new access specifier in the derived class.

Consider the following example with a base class Base:

#include <iostream>

class Base {
private:
    int m_value;

public:
    Base(int value) : m_value(value) {}

protected:
    void printValue() const { std::cout << m_value; }
};

In this case, Base::printValue() is declared as protected, making it accessible only to Base and its derived classes. Now, let's define a derived class Derived that changes the access specifier of printValue() to public:

class Derived : public Base {
public:
    Derived(int value) : Base(value) {}

    // Changing the access specifier of Base::printValue to public
    using Base::printValue;
};

Now, the following code will work:

int main() {
    Derived derived{7};
    derived.printValue();  // Prints 7
    return 0;
}

This demonstrates that by using a using declaration, we can alter the access specifier of an inherited member.

Hiding Functionality

In C++, it's not possible to remove or restrict functionality from a base class directly, but it's feasible to hide functionality in a derived class by changing the access specifier. For example, making a public member private in the derived class:

#include <iostream>

class Base {
public:
    int m_value;
};

class Derived : public Base {
private:
    using Base::m_value;

public:
    Derived(int value) : Base(value) {}
};

In this case, attempting to access, m_value directly in the derived class will result in an error, enhancing encapsulation.

However, it's essential to note that while m_value is private in the derived class, it remains pubic in the base class. Thus, the encapsulation in the derived class can be bypassed by casting to Base& and accessing the member directly.

Deleting Functions in the Derived Class

Functions in the derived class can be marked as deleted, preventing them from being called through a derived object:

#include <iostream>
class Base
{
private:
	int m_value {};

public:
	Base(int value)
		: m_value { value }
	{
	}

	int getValue() const { return m_value; }
};

class Derived : public Base
{
public:
	Derived(int value)
		: Base { value }
	{
	}


	int getValue() const = delete; // mark this function as inaccessible
};

int main()
{
	Derived derived { 7 };

	// The following won't work because getValue() has been deleted!
	std::cout << derived.getValue();

	return 0;
}

In this example, attempting to call derived.getValue() will result in a compilation error. However, the Base version of getValue() remains accessible, allowing it to be called using Base::getValue() or by upcasting Derived to a Base() reference.