Private inheritance renders class inaccessible

G

Guest

The following code does not compile:

class X {};

class Y : private X {};

class Z : public Y
{
public:
Z(X&) {} // problem here
};

Both GCC 3.3 and Comeau Online give the same error:

test.cpp: In constructor `Z::Z(X&)':
test.cpp:1: error: `class X' is inaccessible
test.cpp:8: error: within this context

I can fix the error by changing the broken ctor to Z:):X&) to
explicitly refer to the global class ::X, but I don't understand why I
have to. Can someone explain why private inheritance makes X
inaccessible in this situation?

Thanks.
 
A

Alf P. Steinbach

* (e-mail address removed):
The following code does not compile:

class X {};

class Y : private X {};

class Z : public Y
{
public:
Z(X&) {} // problem here
};

Both GCC 3.3 and Comeau Online give the same error:

test.cpp: In constructor `Z::Z(X&)':
test.cpp:1: error: `class X' is inaccessible
test.cpp:8: error: within this context

I can fix the error by changing the broken ctor to Z:):X&) to
explicitly refer to the global class ::X, but I don't understand why I
have to. Can someone explain why private inheritance makes X
inaccessible in this situation?

It's not obvious. But last time we rehashed this in this group (I posed the
question, just as mystified as you probably are) a natural explanation was
provided by Victor Bazarov, I think it was. Namely that the inheritance for Y
introduces the name X in the class, and ordinary access rules apply when
referring to X that way -- as a name in the class. Qualifying X,
essentially referring to it via another route, fixes that. I can sort of
understand how that results from the detailed technical rules, but I think
that if that explanation is correct, and nothing so far has indicated that it
could be incorrect, then it's a language design bug... ;-)
 
V

Victor Bazarov

The following code does not compile:

class X {};

class Y : private X {};

class Z : public Y
{
public:
Z(X&) {} // problem here
};

Both GCC 3.3 and Comeau Online give the same error:

test.cpp: In constructor `Z::Z(X&)':
test.cpp:1: error: `class X' is inaccessible
test.cpp:8: error: within this context

I can fix the error by changing the broken ctor to Z:):X&) to
explicitly refer to the global class ::X, but I don't understand why I
have to. Can someone explain why private inheritance makes X
inaccessible in this situation?

The name 'X' (without qualification) is inserted into class X's scope when
you define it. That name becomes a member for the purposes of name
lookup. In 'Y' that member is _inherited_, but made *private*. In 'Z' it
is inherited again, but is inaccessible.

Now, when you qualify the name (by means of the name resolution operator,
colon-colon), you issue an explicit instruction to your compiler as to
which 'X' out of two (one in the global scope and the other in the class
scope) to choose. Since the global one is accessible, you have no problem
like with the member. According to name lookup rules, however, the member
is preferred when an unqualified name is used.

V
 
M

Mark P

Victor said:
The name 'X' (without qualification) is inserted into class X's scope when
you define it. That name becomes a member for the purposes of name
lookup. In 'Y' that member is _inherited_, but made *private*. In 'Z' it
is inherited again, but is inaccessible.

Now, when you qualify the name (by means of the name resolution operator,
colon-colon), you issue an explicit instruction to your compiler as to
which 'X' out of two (one in the global scope and the other in the class
scope) to choose. Since the global one is accessible, you have no problem
like with the member. According to name lookup rules, however, the member
is preferred when an unqualified name is used.

V

Am I way off the mark in thinking that is similar in spirit to the
situation where, for example, defining a function foo() in a derived
class hides not only foo() in the base class but any other overloaded
versions of foo (say, foo(int)) in the base class too?

It seems that C++ is at least consistent here, in that it stops looking
for a name as soon as it finds it in any scope, even if the found
instance is not appropriate/useful/sensible.

As to motivation (which someone else brought up elsewhere in this
thread), I've seen it argued that this is sensible behavior in the case
of function overloading as it prevents a deeply derived class from
accidentally invoking a function about whose existence it is perhaps
unaware. Can the same argument be made in this case?

Mark
 
V

Victor Bazarov

Mark said:
[...]
Am I way off the mark in thinking that is similar in spirit to the
situation where, for example, defining a function foo() in a derived
class hides not only foo() in the base class but any other overloaded
versions of foo (say, foo(int)) in the base class too?

Name hides another name. Arguments have nothing to do with it.
'foo' member function in a derived class would hide 'foo' data member
just as well.
It seems that C++ is at least consistent here, in that it stops
looking for a name as soon as it finds it in any scope, even if the
found instance is not appropriate/useful/sensible.

That is not always so. The rules aren't that simple, anyway.
As to motivation (which someone else brought up elsewhere in this
thread), I've seen it argued that this is sensible behavior in the
case of function overloading as it prevents a deeply derived class
from accidentally invoking a function about whose existence it is
perhaps unaware. Can the same argument be made in this case?

Generally speaking, you're correct. The big deal would be if the
meaning (or the behaviour) of the "other" X (or foo) changed, there
should be no effect on the class who defines its own. Now, whether
it applies here I am not sure, but straight-forwardness of name
lookup is probably important.

V
 
R

Robbie Hatley

The following code does not compile:

class X {};

class Y : private X {};

class Z : public Y
{
public:
Z(X&) {} // problem here
};

Both GCC 3.3 and Comeau Online give the same error:

test.cpp: In constructor `Z::Z(X&)':
test.cpp:1: error: `class X' is inaccessible
test.cpp:8: error: within this context

By using private inheritance, you're telling the compiler you DON'T
want classes derived from Y to have access to their "X" part.

If you want to allow classes derived from Y to access their own
"X" part, you could use protected inheritance instead:

class X
{

};

class Y : protected X
{

};

class Z : public Y
{
public:
Z(X&) {}
};

int main()
{
return 0;
}

You'll find that compiles and runs without error.

--
Cheers,
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top