Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does having a declaration of a private base class render a type name inaccessible?

I am surprised that in the following example declaring Middle's base class private makes that name unavailable as a type in a subsequent derivation.

class Base {
public:
  Base(Base const& b) : i(b.i) {}

  int i;
};

class Middle : private Base {            //<<<<<<<<<<<
public:
  Middle(Base const* p) : Base(*p) {}
};

class Upper : public Middle {
public:
  Upper(Base const* p) : Middle(p) {}    //<<<<<<<<<<<
};

Compiling thusly with g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516...

g++ -std=c++11 privateBase.cpp

I get the following diagnostics:

privateBase.cpp:15:9: error: ‘class Base Base::Base’ is inaccessible within this context
   Upper(Base const* p) : Middle(p) {}
         ^~~~
privateBase.cpp:1:12: note: declared here
 class Base {
            ^

Clearly at the point that Base was used as Middle's base class its name was available as a type. I can understand that when Base is used to denote base class storage that should be private. But having a declaration of a private base class render a type name inaccessible seems, at the very least, unexpected.

like image 392
John Yates Avatar asked Dec 27 '18 18:12

John Yates


People also ask

Can private members be accessed in derived class?

Private members of the base class cannot be used by the derived class unless friend declarations within the base class explicitly grant access to them.

Can a object of a derived class Cannot access private members of base class?

Derived class can not access the private members of it's base class. No type of inheritance allows access to private members. However if you use friend declaration you can do that. Save this answer.


1 Answers

This is intended; see core issue 175, which even added an example illustrating this in [class.access.spec]p5:

[ 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 ] [ 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 ]


This falls out of the interaction between class name injection (for rationale, see Why is there an injected class name?) and the fact that in C++ access control applies after name lookup, not before.

like image 191
T.C. Avatar answered Nov 02 '22 18:11

T.C.