1

Why does an interface have a special visibility in a method due to a private inheritance?

Note that a global specifier :: is required in my derived class.

I don't understand why a method inherits some kind of visibility due to private inheritance. It's totally reasonable that Derived class doesn't have access to Control. But why doesn't it have access through a member either?

class Control
{
public:
    void ModifySomething();
};

class Base : private Control
{
private:
    virtual void Update( Control& i_control );
};

class Derived : public Base
{
private:
    // ----------↓↓
    void Update( ::Control& i_control ) override;
};

Note: I understand we could fix this by composition. But I would like to know why it's defined like that in C++. Could we break const-ness or something?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
dmayola
  • 502
  • 5
  • 16

2 Answers2

3

class Derived doesn't have access to anything private in class Base, so it doesn't have access to class Control through Base. It can, however, access Control directly because it's declared in the same global scope as Derived.

As @formerlyknownas_463035818 comments, there are two paths to Control from Derived but one is blocked due to private access control so the other, global path, is chosen.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • would be correct to say that `Control` is in scope via two different paths and the one that has to be prefered by the compiler is blocked, because it is private? – 463035818_is_not_an_ai Oct 14 '19 at 16:01
  • I don't understand why these two paths exist. Why is it defined like that in the language? private inheritance should be like it doesn't exist to the derived class. However, it does exist because I need to specify the global scope. – dmayola Oct 14 '19 at 17:21
  • Because `Control` is in the global `namespace`, `private`ly inheriting it doesn't change that. – Paul Evans Oct 14 '19 at 19:12
1

According to the C++ 17 Standard (14.1 Access specifiers)

5 [ Note: In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared. The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared. — end note ]

And there is an example similar to your code snippet.

[Example:

class A { };
class B : private A { };
class C : public B {
  A* p; // error: injected-class-name A is inaccessible
  ::A* q; // OK
};

— end example ]

That is the injected class name of the private base class within the derived class definition hides the name of the base class defined in the namespace. And this injected name is private. So the derived class does not have an access to this private injected name.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335