Topic: Q:static type checking & lost privacy


Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/04/07
Raw View
>clamage@Eng.Sun.COM (Steve Clamage) writes:
>
>>I pointed out in another post that the original question about a
>>base-class public virtual function overridden by a derived-class
>>private function violated good design principles. There isn't any
>>sensible interpretation for such code, no matter what the language
>>rule.

 I disagree. I can argue that ALL virtual functions
ought to be private. And I can show you code where I have
a public virtual function of a base class and private
virtual functions in the derived class, which is
definitely sensible and works fine.

 For example:

 struct A { virtual void f()=0; virtual ~A(){} };
 class Impl : public virtual A {
  void f();
  ~Impl(){} // allowed??
 public:
  Impl(){}
 };
 A *a = new Impl;

There's nothing wrong with this kind of code, I do it all the time.
The fact that the derived class virtual is private is
completely irrelevant because I have no intention of EVER
accessing the object other than via the pointer to its
abstract interface definition base class A.

The only member I want public in that class is its constructor.
I WANT to hide the whole class after construction.

The whole class is an implementation detail.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: thp@cs.ucr.edu (Tom Payne)
Date: 1995/04/08
Raw View
Pete Becker (pete@borland.com) wrote:
: In article <3m3vmn$od2@galaxy.ucr.edu>, thp@cs.ucr.edu (Tom Payne) says:
: >
: >Christian Millour (chris@alofi.etca.fr) wrote:
: >[stuff deleted]
: >: This is reminiscent of an other access vs visibility issue
: >: discussed in D&E (well worth reading, as always) 2.10 p 55:
: >
: >: int a; // global a
: >: class X {
: >: private:
: >:    int a;
: >: };
: >: class XX : public X {
: >:    void f() { a = 1; } // refers to X::a, not the global a,
: >:                        // and as such won't compile.
: >: };
: >
: >: Have a look there to decide whether this is a bug or a feature.
: >: It certainly is a potentially nasty trap.
: >[stuff deleted]
: >
: >
: >This becomes especially insidious when class X is part of a
: >well-tested library used by the designer of class XX.  Say that int a
: >is a private member added in a well-tested update of the library.  It
: >would be bad if class XX refused to compile, but in this case it does
: >something much worse: it recompiles to a program with different and
: >unintended behavior.

: Huh? If 'a' is private, XX::f() will not compile. That's a problem,
: certainly, but not a subtle one. Adding public or protected members
: leads to much more serious problems, and should not be done lightly.
:  -- Pete

Oops!!  A totally dumb mistake on my part.  The *insidious* errors
occur when I try to use access control to limit the depth of dynamic
binding in a library package I'm implementing.

Tom Payne





Author: pstemari@erinet.com (Paul J. Ste. Marie)
Date: 1995/04/08
Raw View
In article <3m3vmn$od2@galaxy.ucr.edu>, thp@cs.ucr.edu (Tom Payne)
wrote:
:Christian Millour (chris@alofi.etca.fr) wrote:
:[stuff deleted]
:: This is reminiscent of an other access vs visibility issue
:: discussed in D&E (well worth reading, as always) 2.10 p 55:
[stuff deleted]
:: int a; // global a
:: class X {
:: private:
::    int a;
:: };
:: class XX : public X {
::    void f() { a = 1; } // refers to X::a, not the global a,
::                        // and as such won't compile.
:: };
:[stuff deleted]
:This becomes especially insidious when class X is part of a
:well-tested library used by the designer of class XX.  Say that
:int a is a private member added in a well-tested update of the
:library.  It would be bad if class XX refused to compile, but in
:this case it does something much worse: it recompiles to a program
:with different and unintended behavior.
:
:This has to be classed as a *bug* in the design of C++.

If X::a is private, it won't compile.  If X::a is public/protected,
then it's a bug in the update to class X.  X's protected interface
has been changed and (presumeably) XX's author wasn't notified of
this.

To really keep this from happening, use ::a consistently in derived
classes.

 --Paul J. Ste. Marie, pstemari@well.sf.ca.us, pstemari@erinet.com

The Financial Crimes Enforcement Network claims that they capture every
public posting that has their name ("FinCEN") in it.  I wish them good hunting.





Author: pete@borland.com (Pete Becker)
Date: 1995/04/08
Raw View
In article <3m3vmn$od2@galaxy.ucr.edu>, thp@cs.ucr.edu (Tom Payne) says:
>
>Christian Millour (chris@alofi.etca.fr) wrote:
>[stuff deleted]
>: This is reminiscent of an other access vs visibility issue
>: discussed in D&E (well worth reading, as always) 2.10 p 55:
>
>: int a; // global a
>: class X {
>: private:
>:    int a;
>: };
>: class XX : public X {
>:    void f() { a = 1; } // refers to X::a, not the global a,
>:                        // and as such won't compile.
>: };
>
>: Have a look there to decide whether this is a bug or a feature.
>: It certainly is a potentially nasty trap.
>[stuff deleted]
>
>
>This becomes especially insidious when class X is part of a
>well-tested library used by the designer of class XX.  Say that int a
>is a private member added in a well-tested update of the library.  It
>would be bad if class XX refused to compile, but in this case it does
>something much worse: it recompiles to a program with different and
>unintended behavior.

Huh? If 'a' is private, XX::f() will not compile. That's a problem,
certainly, but not a subtle one. Adding public or protected members
leads to much more serious problems, and should not be done lightly.
 -- Pete





Author: dbinder@bnr.ca (David Binderman)
Date: 1995/04/06
Raw View
Christian Millour (chris@alofi.etca.fr) wrote:
: In article <3lsstq$es2@news.uncc.edu>, pvnadham@uncc.edu (Prasanna V Nadhamuni) writes:
: |>
: |> #include <iostream.h>
: |>
: |> class B {
: |>     public:
: |>         virtual void f() {
: |>  cout<<endl<<"in base class's function"<<endl;
: |>         }
: |> };
: |>
: |> class D : public B {
: |>     private:
: |>         void f() {
: |>  cout<<endl<<"in derived class's function"<<endl;
: |>         }
: |> };
: |>
: |> main()
: |> {
: |>     D derived;
: |>     D* pder = &derived;
: |>     B* pbase = &derived;
: |>
: |>     pbase->f();      // this accesses the derived class's function !!!
: |> //    pder->f();      // rejected at compile time, rightfully so
: |>
: |>     return 1;
: |> }

I've been bitten by this one too. Newbies get very confused when
private member functions get executed by class customers.

Beyond pointing them at D&E, which I've just read and doesn't
seem to help, does anyone have any good rationale for this bug/feature ?

: public/protected/private directives only control access, not
: visibility. Access control is performed at compile time as you
: pointed out (pbase->f() granted, pder->f() rejected). The
: virtual dispatch mechanism in turn only concerns itself with
: member visibility. If you can get access to a virtual member of
: a base, you'll be able to invoque any overriden version,
: irrespective of this version's declared accessibility.

I remain not convinced. Why doesn't the compiler just ban
virtual functions at the private level ?

Follows to comp.std.c++ only, please. I don't have time for
comp.lang.c++

Regards

David C Binderman MSc BSc  dbinder@bnr.ca  dbinder@bnr.co.uk  +44 1628 794 887
Object Oriented Design & Analysis with C++, UNIX and C.





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1995/04/06
Raw View
In article 3pj@bmdhh222.bnr.ca, dbinder@bnr.ca (David Binderman) writes:
>
>I remain not convinced. Why doesn't the compiler just ban
>virtual functions at the private level ?


Private virtual functions are very useful. You can provide a single
non-virtual function in a base class that calls private virtual
functions for implementation. Derived classes override the
private helper functions as needed.

I pointed out in another post that the original question about a
base-class public virtual function overridden by a derived-class
private function violated good design principles. There isn't any
sensible interpretation for such code, no matter what the language
rule.

---
Steve Clamage, stephen.clamage@eng.sun.com







Author: b91926@fsgm01.fnal.gov (David Sachs)
Date: 1995/04/06
Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:

...

>I pointed out in another post that the original question about a
>base-class public virtual function overridden by a derived-class
>private function violated good design principles. There isn't any
>sensible interpretation for such code, no matter what the language
>rule.

Isn't that a sensible way to override a public virtual function of a
private base class?





Author: rac@intrigue.com (Robert Coie)
Date: 1995/04/06
Raw View
In article <3m1hen$p11@fsgm01.fnal.gov>, b91926@fsgm01.fnal.gov (David
Sachs) wrote:

: clamage@Eng.Sun.COM (Steve Clamage) writes:
:
: ...
:
: >I pointed out in another post that the original question about a
: >base-class public virtual function overridden by a derived-class
: >private function violated good design principles. There isn't any
: >sensible interpretation for such code, no matter what the language
: >rule.
:
: Isn't that a sensible way to override a public virtual function of a
: private base class?

Sure, but the original problem involved the illusion of access violation
caused by invoking the function through a pointer to the base class in
which it was public.  If the inheritance is private, the derived->base
conversion is not publicly accessible, so I don't see how the problem
would come about.

Robert Coie                              rac@intrigue.com
Implementor, Intrigue Corporation     AppleLink: INTRIGUE





Author: thp@cs.ucr.edu (Tom Payne)
Date: 1995/04/07
Raw View
Christian Millour (chris@alofi.etca.fr) wrote:
[stuff deleted]
: This is reminiscent of an other access vs visibility issue
: discussed in D&E (well worth reading, as always) 2.10 p 55:

: int a; // global a
: class X {
: private:
:    int a;
: };
: class XX : public X {
:    void f() { a = 1; } // refers to X::a, not the global a,
:                        // and as such won't compile.
: };

: Have a look there to decide whether this is a bug or a feature.
: It certainly is a potentially nasty trap.
[stuff deleted]


This becomes especially insidious when class X is part of a
well-tested library used by the designer of class XX.  Say that int a
is a private member added in a well-tested update of the library.  It
would be bad if class XX refused to compile, but in this case it does
something much worse: it recompiles to a program with different and
unintended behavior.

This has to be classed as a *bug* in the design of C++.

Tom Payne





Author: dbinder@bnr.ca (David Binderman)
Date: 1995/04/07
Raw View
Steve Clamage (clamage@Eng.Sun.COM) wrote:
: In article 3pj@bmdhh222.bnr.ca, dbinder@bnr.ca (David Binderman) writes:
: >I remain not convinced. Why doesn't the compiler just ban
: >virtual functions at the private level ?

: Private virtual functions are very useful. You can provide a single
: non-virtual function in a base class that calls private virtual
: functions for implementation. Derived classes override the
: private helper functions as needed.

Fair enough.

: I pointed out in another post that the original question about a
: base-class public virtual function overridden by a derived-class
: private function violated good design principles. There isn't any
: sensible interpretation for such code, no matter what the language
: rule.

Sounds like omething else a good compiler could produce a warning for.
I won't hold my breath.

Regards

David C Binderman MSc BSc  dbinder@bnr.ca  dbinder@bnr.co.uk  +44 1628 794 887
Object Oriented Design & Analysis with C++, UNIX and C.





Author: chris@alofi.etca.fr (Christian Millour)
Date: 1995/04/06
Raw View
In article <3lsstq$es2@news.uncc.edu>, pvnadham@uncc.edu (Prasanna V Nadhamuni) writes:
|>
|> #include <iostream.h>
|>
|> class B {
|>     public:
|>         virtual void f() {
|>  cout<<endl<<"in base class's function"<<endl;
|>         }
|> };
|>
|> class D : public B {
|>     private:
|>         void f() {
|>  cout<<endl<<"in derived class's function"<<endl;
|>         }
|> };
|>
|> main()
|> {
|>     D derived;
|>     D* pder = &derived;
|>     B* pbase = &derived;
|>
|>     pbase->f();      // this accesses the derived class's function !!!
|> //    pder->f();      // rejected at compile time, rightfully so
|>
|>     return 1;
|> }
|>
|> Q : the call  'pbase->f()' manages to override the privacy of the function f()
|>     in the derived class.  but if the f() in the base class were not virtual,
|>     'pbase->f()' simply calls the base function f() !!
|>     what mechanism makes that possible ?
|>     is this a consequence of static type checking? [based on base's
|>     access rules ?]
|>

public/protected/private directives only control access, not
visibility. Access control is performed at compile time as you
pointed out (pbase->f() granted, pder->f() rejected). The
virtual dispatch mechanism in turn only concerns itself with
member visibility. If you can get access to a virtual member of
a base, you'll be able to invoque any overriden version,
irrespective of this version's declared accessibility.

This is reminiscent of an other access vs visibility issue
discussed in D&E (well worth reading, as always) 2.10 p 55:

int a; // global a
class X {
private:
   int a;
};
class XX : public X {
   void f() { a = 1; } // refers to X::a, not the global a,
                       // and as such won't compile.
};

Have a look there to decide whether this is a bug or a feature.
It certainly is a potentially nasty trap.

Cross-posted to comp.std.c++ since I wonder whether the draft
standard has anything to say about it.

Regards,

--chris@etca.fr





Author: maney@MCS.COM (Martin Maney)
Date: 1995/04/06
Raw View
David Binderman (dbinder@bnr.ca) wrote:

[much snipped and examples reduced:]

> : |> class B {
> : |>     public:
> : |>         virtual void f() {

> : |> class D : public B {
> : |>     private:
> : |>         void f() {

> : |>     D derived;
> : |>     D* pder = &derived;
> : |>     B* pbase = &derived;
> : |>
> : |>     pbase->f();      // this accesses the derived class's function !!!
> : |> //    pder->f();      // rejected at compile time, rightfully so

> I've been bitten by this one too. Newbies get very confused when
> private member functions get executed by class customers.

> Beyond pointing them at D&E, which I've just read and doesn't
> seem to help, does anyone have any good rationale for this bug/feature ?

I don't think there is a good rationale possible, since the real problem
is the design of those classes.  As written they have no business being
related by inheritance like that.  You might find Cargill's _C++
Programming Style_ useful: unnecesaary and wrong-headed inheritance gets
a lot of discussion there.  Or Meyers' _Effective C++_ - item 35 seems
immediately applicable to the above, for example.

The root of the problem is that D is-not-A B: foo() is not part of D's
public interface.  The weirdness of the the example is just the
reflection of the weirdness of this design bug/feature, if you'll pardon
the expression.  :-)

> I remain not convinced. Why doesn't the compiler just ban
> virtual functions at the private level ?

Because they're useful.  Consider a bit of implementation that is called
from many other member functions, but should not be part of the public
interface: it has to be private (or protected, but I think we can gloss
over that for now).  But now, what if that functions needs to be
different for different derived classes?  It will have to be private and
virtual, no?  Works just fine!