Topic: Using base class pointers from derived class


Author: Daniel Schepler <dks2@cs.wustl.edu>
Date: 1997/07/17
Raw View
jim.hyslop@leitch.com (Jim Hyslop) writes:

> In article <m3iuyn4pxp.fsf@frobnitz.wustl.edu> on 07 Jul 1997 10:44:17
> PDT, daniel@frobnitz.wustl.edu says...
> > I recently attempted to write code like this:
> >
> > class base {
> >   protected:
> >     void foo(int);
> > };
> >
> > class derived : public base {
> >   private:
> >     base *obj;
> >   public:
> >     void doFoo(int a) {
> >       foo(a);
> >       obj->foo(a);   // Access error
> >     }
> > };
> >
> > It seems that according to the C++ draft standard, the first access in
> > doFoo is legal because base::foo is also accessible as a protected
> > member of derived.  However, the second access is illegal, since
> > derived::doFoo is not a member function of base.
> [snip]
>
> One way to look at protected members is to remember that the access to
> the member variable can *only* be prefixed by "this->" - no other
> prefix is allowed.
>
> To rewrite your functions ever so slightly, while maintaining the
> same semantics:
>      void doFoo(int a) {
>        this->foo(a);
>        obj->foo(a);   // Access error
>      }
> the answer becomes clear:  the first access is this-> but the second
> is not.

According to the C++ standard, the access lookup is based on class
name, not whether the object referenced is "this" or not.  My example
would work perfectly well with "derived *obj;" instead of "base *obj;"

When I wrote the original article, I was looking at section 11.2.4 of
the Dec. 1996 draft standard (as well as 11.2.1 to some extent), and I
saw no reason that these sections would allow my program to be
considered well-formed.  Later, I saw section 11.5, which explicitly
forbids this access.  (So was my interpretation of 11.2 wrong, or is
11.5 redundant in this case?)  I suppose there are arguments to
disallow this access.  However, all the arguments I can think of would
apply just as well if obj were of type "derived *" instead of
"base *", but the case with "derived *obj" is well-established as valid
C++.

Also, this section raises another question in my mind.  It explicitly
allows me to rewrite doFoo as

   void doFoo(int a) {
     void (base::*fooptr)(int) = foo;

     (this->*fooptr)(a);
     (obj->*fooptr)(a);
   }

So what's the semantic difference between being able to take a pointer
to foo and call it on obj, or being able to call obj->foo() directly?
Also, if I had happened to override foo in class "derived", this would
no longer work, and neither would replacing "foo" in the initializer
with "base::foo", which seems nonobvious behavior to me.
--
Daniel Schepler                      "Please don't disillusion me.  I
dks2@cs.wustl.edu                     haven't had breakfast yet."
                                        -- Orson Scott Card
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Srinivas Vobilisetti <Srinivas.Vobilisetti@mci.com>
Date: 1997/07/18
Raw View
Daniel Schepler wrote:
 >
 > jim.hyslop@leitch.com (Jim Hyslop) writes:
 >
 > > In article <m3iuyn4pxp.fsf@frobnitz.wustl.edu> on 07 Jul 1997 10:44:17
 > > PDT, daniel@frobnitz.wustl.edu says...
 > > > I recently attempted to write code like this:
 > > >
 > > > class base {
 > > >   protected:
 > > >     void foo(int);
 > > > };
 > > >
 > > > class derived : public base {
 > > >   private:
 > > >     base *obj;
 > > >   public:
 > > >     void doFoo(int a) {
 > > >       foo(a);
 > > >       obj->foo(a);   // Access error
 > > >     }
 > > > };
 > > >
 > > > It seems that according to the C++ draft standard, the first access in
 > > > doFoo is legal because base::foo is also accessible as a protected
 > > > member of derived.  However, the second access is illegal, since
 > > > derived::doFoo is not a member function of base.
 > > [snip]
 > >
 > > One way to look at protected members is to remember that the access to
 > > the member variable can *only* be prefixed by "this->" - no other
 > > prefix is allowed.
 > >
 > > To rewrite your functions ever so slightly, while maintaining the
 > > same semantics:
 > >      void doFoo(int a) {
 > >        this->foo(a);
 > >        obj->foo(a);   // Access error
 > >      }
 > > the answer becomes clear:  the first access is this-> but the second
 > > is not.
 >
 > According to the C++ standard, the access lookup is based on class
 > name, not whether the object referenced is "this" or not.  My example
 > would work perfectly well with "derived *obj;" instead of "base *obj;"
 >
 > When I wrote the original article, I was looking at section 11.2.4 of
 > the Dec. 1996 draft standard (as well as 11.2.1 to some extent), and I
 > saw no reason that these sections would allow my program to be
 > considered well-formed.  Later, I saw section 11.5, which explicitly
 > forbids this access.  (So was my interpretation of 11.2 wrong, or is
 > 11.5 redundant in this case?)  I suppose there are arguments to
 > disallow this access.  However, all the arguments I can think of would
 > apply just as well if obj were of type "derived *" instead of
 > "base *", but the case with "derived *obj" is well-established as valid
 > C++.
 >
 > Also, this section raises another question in my mind.  It explicitly
 > allows me to rewrite doFoo as
 >
 >    void doFoo(int a) {
 >      void (base::*fooptr)(int) = foo;
 >
 >      (this->*fooptr)(a);
 >      (obj->*fooptr)(a);
 >    }
 >
 > So what's the semantic difference between being able to take a pointer
 > to foo and call it on obj, or being able to call obj->foo() directly?
 > Also, if I had happened to override foo in class "derived", this would
 > no longer work, and neither would replacing "foo" in the initializer
 > with "base::foo", which seems nonobvious behavior to me.

Is it some form of casting away the protection barrier or what (like
casting away the constness, etc)? I tried this example on my DEC
compiler and it worked with a small change.

    void doFoo(int a) {
      void (base::*fooptr)(int) = &base::foo; // I changed this line

      (this->*fooptr)(a);
      (obj->*fooptr)(a);
    }

But it does not work if I add the line "obj->foo(a);".

Srinivas
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: jim.hyslop@leitch.com (Jim Hyslop)
Date: 1997/07/15
Raw View
In article <m3iuyn4pxp.fsf@frobnitz.wustl.edu> on 07 Jul 1997 10:44:17
PDT, daniel@frobnitz.wustl.edu says...
> I recently attempted to write code like this:
>
> class base {
>   protected:
>     void foo(int);
> };
>
> class derived : public base {
>   private:
>     base *obj;
>   public:
>     void doFoo(int a) {
>       foo(a);
>       obj->foo(a);   // Access error
>     }
> };
>
> It seems that according to the C++ draft standard, the first access in
> doFoo is legal because base::foo is also accessible as a protected
> member of derived.  However, the second access is illegal, since
> derived::doFoo is not a member function of base.
[snip]

One way to look at protected members is to remember that the access to
the member variable can *only* be prefixed by "this->" - no other
prefix is allowed.

To rewrite your functions ever so slightly, while maintaining the
same semantics:
     void doFoo(int a) {
       this->foo(a);
       obj->foo(a);   // Access error
     }
the answer becomes clear:  the first access is this-> but the second
is not.

An object can only access protected members of its *own* parents, not
some other object's parents.  Just like the family fortune - you can
use whatever fortune you inherit from your parent(s), but you can't
touch anyone else's family fortune, even if you are the same class as
that person.  Unless, of course, you are good friends with the other
object's parents.

--
Jim Hyslop O-

Imagination is more important than knowledge.
   -- Albert Einstein

Don't pass on that email about someone dying of cancer or a "new
super-powerful computer virus" until you check out the Internet Hoax
page http://ciac.llnl.gov/ciac/CIACHoaxes.html first!
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Srinivas Vobilisetti <Srinivas.Vobilisetti@mci.com>
Date: 1997/07/16
Raw View
Jim Hyslop wrote:
 >
 > In article <m3iuyn4pxp.fsf@frobnitz.wustl.edu> on 07 Jul 1997 10:44:17
 > PDT, daniel@frobnitz.wustl.edu says...
 > > I recently attempted to write code like this:
 > >
 > > class base {
 > >   protected:
 > >     void foo(int);
 > > };
 > >
 > > class derived : public base {
 > >   private:
 > >     base *obj;
 > >   public:
 > >     void doFoo(int a) {
 > >       foo(a);
 > >       obj->foo(a);   // Access error
 > >     }
 > > };
 > >
 > > It seems that according to the C++ draft standard, the first access in
 > > doFoo is legal because base::foo is also accessible as a protected
 > > member of derived.  However, the second access is illegal, since
 > > derived::doFoo is not a member function of base.
 > [snip]
 >
 > One way to look at protected members is to remember that the access to
 > the member variable can *only* be prefixed by "this->" - no other
 > prefix is allowed.
 >
 > To rewrite your functions ever so slightly, while maintaining the
 > same semantics:
 >      void doFoo(int a) {
 >        this->foo(a);
 >        obj->foo(a);   // Access error
 >      }
 > the answer becomes clear:  the first access is this-> but the second
 > is not.
 >
 > An object can only access protected members of its *own* parents, not
 > some other object's parents.  Just like the family fortune - you can
 > use whatever fortune you inherit from your parent(s), but you can't
 > touch anyone else's family fortune, even if you are the same class as
 > that person.  Unless, of course, you are good friends with the other
 > object's parents.
 >

No. you can access protected base class members of other objects as long
as the other object's static type is same as of your class or a class
derived from your class. For specific information, refer to DWP96
section 11.5 Protected member access.

Srinivas
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Daniel Schepler <daniel@frobnitz.wustl.edu>
Date: 1997/07/07
Raw View
I recently attempted to write code like this:

class base {
  protected:
    void foo(int);
};

class derived : public base {
  private:
    base *obj;
  public:
    void doFoo(int a) {
      foo(a);
      obj->foo(a);   // Access error
    }
};

It seems that according to the C++ draft standard, the first access in
doFoo is legal because base::foo is also accessible as a protected
member of derived.  However, the second access is illegal, since
derived::doFoo is not a member function of base.

However, to me it seems inconsistent that base::foo is, in effect,
accessible within *this, but not within *obj.  And my perception of
inheritance before I read the standard was always that the first
access was legal because base::foo was accessible because of the
inheritance, instead of the inheritance making base::foo into a
protected member function of derived, and thus accessible from
derived::doFoo.  (The first explanation seems clearer and more
intuitive to me.)

Anyway, I think this type of access should be allowed in this
context.
--
Daniel Schepler                      "Please don't disillusion me.  I
dks2@cs.wustl.edu                     haven't had breakfast yet."
                                         -- Orson Scott Card
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: kuehl@horn.informatik.uni-konstanz.de (Dietmar Kuehl)
Date: 1997/07/07
Raw View
Hi,
Daniel Schepler (daniel@frobnitz.wustl.edu) wrote:

: class base {
:   protected:
:     void foo(int);
: };

: class derived : public base {
:   private:
:     base *obj;
:   public:
:     void doFoo(int a) {
:       foo(a);
:       obj->foo(a);   // Access error
:     }
: };

: It seems that according to the C++ draft standard, the first access in
: doFoo is legal because base::foo is also accessible as a protected
: member of derived.  However, the second access is illegal, since
: derived::doFoo is not a member function of base.

Not exactly. The second access is illegal because it is unknown whether
'obj' is indeed a 'derived'. ... and it makes a lot sense to deny
access in this case: If 'obj' is actually pointing to an object of
another class, say 'sibling', also derived from 'base', it would be
possible to access 'sibling's state using a 'derived' member function.
Since 'sibling' and 'derived' are not really related, access to the
protected part of 'sibling', or any other class derived from 'base', by
a method of 'derived' is denied.

: Anyway, I think this type of access should be allowed in this
: context.

I would definitely be opposed to allow this access, although I once
also wanted to have it: It would break encapsulation.
--
<mailto:dietmar.kuehl@uni-konstanz.de>
<http://www.informatik.uni-konstanz.de/~kuehl/>
I'm seeking a new employment - See my homepage for details
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]