Access of base class' private base class: qualification required, why

Discussion in 'C++' started by Alf P. Steinbach, Sep 3, 2005.

  1. #include <iostream>

    struct Belcher
    {
    int x;
    void belch() { std::cout << x << std::endl; }
    Belcher( int anX ): x( anX ) {}
    };

    struct Person: private Belcher { Person(): Belcher( 666 ) {} };

    struct Viking: Person
    {
    void eat() {}
    void dine( bool belch )
    {
    eat();
    if( belch )
    {
    Viking* pv = this;
    ::Belcher* p = :):Belcher*) pv;
    // Why is qualification necessary here?
    }
    }
    };

    int main()
    {
    Viking v;
    Viking* pv = &v;
    Belcher* p = (Belcher*) pv;
    p->belch();
    }

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

  2. Alf P. Steinbach wrote:
    > #include <iostream>
    >
    > struct Belcher
    > {
    > int x;
    > void belch() { std::cout << x << std::endl; }
    > Belcher( int anX ): x( anX ) {}
    > };
    >
    > struct Person: private Belcher { Person(): Belcher( 666 ) {} };
    >
    > struct Viking: Person
    > {
    > void eat() {}
    > void dine( bool belch )
    > {
    > eat();
    > if( belch )
    > {
    > Viking* pv = this;
    > ::Belcher* p = :):Belcher*) pv;
    > // Why is qualification necessary here?


    By qualifying you explicitly specify to use the global name 'Belcher'
    not the 'Belcher' name brought into the scope of this class from the
    Person's scope -- the grandfather class. If you remember, a name in
    scope _hides_ the name in the enclosing scope. 'Belcher' in 'Viking'
    comes from 'Person' and in 'Person' it hides '::Belcher'.

    I am a bit perplexed by the need to do that C-style cast. If the base
    class is private, you're not supposed to use it. Why force the code
    into doing something that is purposely not there?

    > }
    > }
    > };
    >
    > int main()
    > {
    > Viking v;
    > Viking* pv = &v;
    > Belcher* p = (Belcher*) pv;
    > p->belch();
    > }


    V
     
    Victor Bazarov, Sep 3, 2005
    #2
    1. Advertising

  3. * Victor Bazarov:
    > Alf P. Steinbach wrote:
    > > #include <iostream>
    > >
    > > struct Belcher
    > > {
    > > int x;
    > > void belch() { std::cout << x << std::endl; }
    > > Belcher( int anX ): x( anX ) {}
    > > };
    > >
    > > struct Person: private Belcher { Person(): Belcher( 666 ) {} };
    > >
    > > struct Viking: Person
    > > {
    > > void eat() {}
    > > void dine( bool belch )
    > > {
    > > eat();
    > > if( belch )
    > > {
    > > Viking* pv = this;
    > > ::Belcher* p = :):Belcher*) pv;
    > > // Why is qualification necessary here?

    >
    > By qualifying you explicitly specify to use the global name 'Belcher'
    > not the 'Belcher' name brought into the scope of this class from the
    > Person's scope -- the grandfather class. If you remember, a name in
    > scope _hides_ the name in the enclosing scope.


    Well, yes, but it isn't really in scope in Viking when it's private in
    Person, is it? I mean, that's an implementation detail of Person. It
    shouldn't affect Viking, except for virtual member functions.


    > 'Belcher' in 'Viking'
    > comes from 'Person' and in 'Person' it hides '::Belcher'.
    >
    > I am a bit perplexed by the need to do that C-style cast. If the base
    > class is private, you're not supposed to use it. Why force the code
    > into doing something that is purposely not there?


    Just to do the C cast...

    --
    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 3, 2005
    #3
  4. Alf P. Steinbach

    John Carson Guest

    "Alf P. Steinbach" <> wrote in message
    news:
    > * Victor Bazarov:
    >> Alf P. Steinbach wrote:
    >>> #include <iostream>
    >>>
    >>> struct Belcher
    >>> {
    >>> int x;
    >>> void belch() { std::cout << x << std::endl; }
    >>> Belcher( int anX ): x( anX ) {}
    >>> };
    >>>
    >>> struct Person: private Belcher { Person(): Belcher( 666 ) {} };
    >>>
    >>> struct Viking: Person
    >>> {
    >>> void eat() {}
    >>> void dine( bool belch )
    >>> {
    >>> eat();
    >>> if( belch )
    >>> {
    >>> Viking* pv = this;
    >>> ::Belcher* p = :):Belcher*) pv;
    >>> // Why is qualification necessary here?

    >>
    >> By qualifying you explicitly specify to use the global name 'Belcher'
    >> not the 'Belcher' name brought into the scope of this class from the
    >> Person's scope -- the grandfather class. If you remember, a name in
    >> scope _hides_ the name in the enclosing scope.

    >
    > Well, yes, but it isn't really in scope in Viking when it's private in
    > Person, is it? I mean, that's an implementation detail of Person. It
    > shouldn't affect Viking, except for virtual member functions.


    By 10.2, name lookup takes place before access control. If I have
    interpreted this correctly, this means that the fact that Belcher is private
    in Person is irrelevant for name lookup purposes.

    What surprises me is that inheriting from Belcher apparently has the effect
    of declaring a Belcher type that is distinct from the Belcher type declared
    at global scope. But I guess this makes sense; after all a base subobject
    can be of zero size, whereas a free-standing object of the same-named class
    cannot be of zero size.


    --
    John Carson
     
    John Carson, Sep 3, 2005
    #4
  5. John Carson wrote:
    > [...]
    > What surprises me is that inheriting from Belcher apparently has the
    > effect of declaring a Belcher type that is distinct from the Belcher
    > type declared at global scope.


    Why does that surprise you?

    3.4/3 says that the name of the class is a member of that class for
    the purposes of name lookup. Since all members are inherited (unless
    they are hidden), the name of any base class is considered a member
    of the derived class. If you inherit the derived class again, the
    member of it will become a member of the next derived class and so on.

    > But I guess this makes sense; after
    > all a base subobject can be of zero size, whereas a free-standing
    > object of the same-named class cannot be of zero size.


    I am not sure how you stitch sizes into that... It's simpler.

    class A {};

    class B { // I purposely didn't inherit B from A
    typedef A A; // that was happens if inherited; choose your
    // access specifier. 'A' is now a member of 'B'
    };

    class C : B {
    // A is a member here too
    };

    int main() {
    A a; // OK
    B::A ba; // cannot access private name
    C::A ca; // same error
    }

    V
     
    Victor Bazarov, Sep 3, 2005
    #5
  6. * Victor Bazarov:
    > John Carson wrote:
    > > [...]
    > > What surprises me is that inheriting from Belcher apparently has the
    > > effect of declaring a Belcher type that is distinct from the Belcher
    > > type declared at global scope.

    >
    > Why does that surprise you?
    >
    > 3.4/3 says that the name of the class is a member of that class for
    > the purposes of name lookup. Since all members are inherited (unless
    > they are hidden), the name of any base class is considered a member
    > of the derived class. If you inherit the derived class again, the
    > member of it will become a member of the next derived class and so on.
    >
    > > But I guess this makes sense; after
    > > all a base subobject can be of zero size, whereas a free-standing
    > > object of the same-named class cannot be of zero size.

    >
    > I am not sure how you stitch sizes into that... It's simpler.
    >
    > class A {};
    >
    > class B { // I purposely didn't inherit B from A
    > typedef A A; // that was happens if inherited; choose your
    > // access specifier. 'A' is now a member of 'B'
    > };
    >
    > class C : B {
    > // A is a member here too
    > };
    >
    > int main() {
    > A a; // OK
    > B::A ba; // cannot access private name
    > C::A ca; // same error
    > }


    Thanks Victor, you cleared this up, and my frust-o-meter is now starting to
    calm down. :)

    --
    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 3, 2005
    #6
  7. Alf P. Steinbach

    John Carson Guest

    "Victor Bazarov" <> wrote in message
    news:p
    > John Carson wrote:
    >> [...]
    >> What surprises me is that inheriting from Belcher apparently has the
    >> effect of declaring a Belcher type that is distinct from the Belcher
    >> type declared at global scope.

    >
    > Why does that surprise you?


    Sheer ignorance on my part Victor.

    > 3.4/3 says that the name of the class is a member of that class for
    > the purposes of name lookup. Since all members are inherited (unless
    > they are hidden), the name of any base class is considered a member
    > of the derived class. If you inherit the derived class again, the
    > member of it will become a member of the next derived class and so on.


    I hunted around for a section such as you cite, but couldn't find it. Thanks
    for the info.


    --
    John Carson
     
    John Carson, Sep 3, 2005
    #7
    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. Andrew R. Thomas-Cramer
    Replies:
    8
    Views:
    533
    Roedy Green
    Jul 11, 2003
  2. Chris
    Replies:
    0
    Views:
    526
    Chris
    May 28, 2004
  3. J.T. Conklin
    Replies:
    1
    Views:
    443
    David Hilsee
    Aug 11, 2004
  4. Lionel B
    Replies:
    4
    Views:
    343
    Lionel B
    Apr 7, 2005
  5. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,003
    Smokey Grindel
    Dec 2, 2006
Loading...

Share This Page