Private inheritance renders class inaccessible

Discussion in 'C++' started by spam@grog.net, Sep 23, 2005.

  1. 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.
     
    , Sep 23, 2005
    #1
    1. Advertising

  2. * :
    > 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... ;-)

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Sep 23, 2005
    #2
    1. Advertising

  3. wrote:
    > 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
     
    Victor Bazarov, Sep 23, 2005
    #3
  4. Alf P. Steinbach wrote:
    > [...] Namely that the inheritance for Y
    > introduces the name X in the class,


    Actually 'X' has its own name as a member, 'Y' just inherits it.
    Relevant clause is 9, paragraph 2.

    > [..]


    V
     
    Victor Bazarov, Sep 23, 2005
    #4
  5. Guest

    Thanks Victor. I won't pretend this is obvious, but I the reasoning
    makes sense.
     
    , Sep 23, 2005
    #5
  6. Mark P Guest

    Victor Bazarov wrote:
    > wrote:
    >
    >> 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


    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
     
    Mark P, Sep 24, 2005
    #6
  7. Mark P wrote:
    > [...]
    > 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
     
    Victor Bazarov, Sep 24, 2005
    #7
  8. <> wrote in message
    news:...
    > 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
     
    Robbie Hatley, Sep 24, 2005
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. qazmlp
    Replies:
    19
    Views:
    797
    Daniel T.
    Feb 4, 2004
  2. DaveLessnau
    Replies:
    3
    Views:
    428
    Howard
    May 16, 2005
  3. Stefan Weber
    Replies:
    9
    Views:
    419
    Stefan Weber
    May 29, 2007
  4. Stefan Weber
    Replies:
    2
    Views:
    420
    Howard
    May 22, 2007
  5. Stefan Weber
    Replies:
    0
    Views:
    381
    Stefan Weber
    May 22, 2007
Loading...

Share This Page