Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why a simple mention of base pointer/reference in subsequent privately derived classes is forbidden?

struct B {};
struct D : private B {
  B* fun () { return new D; }  // ok
}
struct DD : public D {
  B* foo () { return 0; } // error: ‘struct B B::B’ is inaccessible !
};

This error seems unreasonable to me. If we can use simple B* in global scope then why not in its privately derived classes? g++ demo.

We are Not trying to convert DD* to B*, which is forbidden by the language rules (this, this, this are related questions).
Note that, if I change B* foo() to int foo(), things go fine.

like image 800
iammilind Avatar asked Dec 18 '12 05:12

iammilind


People also ask

Why can't a derived pointer reference a base object?

similarly a derived object is a base class object (as it's a sub class), so it can be pointed to by a base class pointer. However, a base class object is not a derived class object so it can't be assigned to a derived class pointer.

What's the use of a base class pointer pointing to a derived object when the derived class pointer can point to a derived object directly?

Explanation: A base class pointer can point to a derived class object, but we can only access base class member or virtual functions using the base class pointer because object slicing happens when a derived class object is assigned to a base class object.

Can pointers reference objects of different base types?

A pointer reference is polymorphic, since it can reference objects of different dynamic type.


2 Answers

So apparently the compiler thinks B is referring to the private constructor of B rather than the type.

Qualifying B apparently fixes that error:

class B* foo () { return 0; }

or this:

::B* foo () { return 0; }

I don't know why that's happening, but maybe this will help.


Update: maybe it's related to 11.2.4 of standard? The only problem is that my standardese isn't good enough to fully understand it.

(sorry for the image, copy/pasting isn't working for me)

like image 140
Pubby Avatar answered Sep 19 '22 08:09

Pubby


A quick look-up for injected-class-name in the Standard yields:

§11.1 [class.access.spec]

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 ]

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

I believe this is eerily close to your example ;)


Note clang 3.0's stack, which is slightly more explicit:

$ clang++ -fsyntax-only test.cpp
test.cpp:6:5: error: 'B' is a private member of 'B'
    B* foo () { return 0; } // error: ‘struct B B::B’ is inaccessible !
    ^
test.cpp:2:12: note: constrained by private inheritance here
struct D : private B {
           ^~~~~~~~~
test.cpp:1:8: note: member is declared here
struct B {};
       ^
1 error generated.

Here we see that B is accessed through D, instead of directly picked up in the global namespace.

like image 23
Matthieu M. Avatar answered Sep 21 '22 08:09

Matthieu M.