Restricting access should be illegal?

  • Follow


Consider the following legal code:

-----------------------
#include <stdio.h>

class A {
   public:
     virtual void Member() { printf("A::Member\n"); }
};

class B : public A {
   private:
     virtual void Member() { printf("B::Member\n"); }
};

int main()
{
     B *b = new B();
//    b->Member();	// error, B::Member is private
     A *a = b;
     a->Member();	// calls B::Member
}
-------------------------

Shouldn't restricting access to an overriding virtual function be an 
error? After all, we can get at it anyway via an implicit conversion. 
Does anyone know of a legitimate design pattern that does this?

-Walter Bright
www.digitalmars.com C, C++, D programming language compilers

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Walter 7/15/2006 10:38:55 AM

Walter Bright wrote:

> class A {
>    public:
>      virtual void Member() { printf("A::Member\n"); }
> };
> 
> class B : public A {
>    private:
>      virtual void Member() { printf("B::Member\n"); }
> };
> 
> int main()
> {
>      B *b = new B();
> //    b->Member();	// error, B::Member is private
>      A *a = b;
>      a->Member();	// calls B::Member
> }


> Shouldn't restricting access to an overriding virtual function be an 
> error? 

No, why? Class B could implement an interface A that is only to be 
called directly thru the interface specification and not thru the 
concrete implementation.

> After all, we can get at it anyway via an implicit conversion.

Right, because for example B implements A, so converting B to an A is fine.

> Does anyone know of a legitimate design pattern that does this?

The advantage would be that anyone using the interface described by A 
shall not be able to use or see the extensions defined by B. You would 
be still able to use the A interface, however very explicitly and 
visibly in the source by turning a B into an A.

So long,
	Thomas

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Thomas 7/15/2006 2:41:20 PM


> Shouldn't restricting access to an overriding virtual function be an
> error? After all, we can get at it anyway via an implicit conversion.


Yes, this kind of implicit conversion also confused me.

But, the static access specifier checking and run-time polymorphic
behavior do not work together very well. I am not sure how much we
will pay for issue an error here (you knows much more than me :-) ),
and even it is feasible, this change will break lots of legacy code,
which depends on this usage intentionally, or unintentionally.


> Does anyone know of a legitimate design pattern that does this?
>


I think Template Method fits here. *All* virtual member should be
kept protected or private and we can provide public template method
interface to the clients. No conversion problem and the derived
classes are free to replace the concrete implementation.

That is, all virtual member should be protected or private by
default. I can not recall who showed this idea first, maybe
Herb Sutter, or James Kanze. And I follow this rule whenever
possible.

Goo


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Jiang 7/15/2006 3:47:43 PM

Thomas Richter wrote:
> > Walter Bright wrote:
> >
>> > > class A {
>> > >    public:
>> > >      virtual void Member() { printf("A::Member\n"); }
>> > > };
>> > >
>> > > class B : public A {
>> > >    private:
>> > >      virtual void Member() { printf("B::Member\n"); }
>> > > };
>> > >
>> > > int main()
>> > > {
>> > >      B *b = new B();
>> > > //    b->Member();	// error, B::Member is private
>> > >      A *a = b;
>> > >      a->Member();	// calls B::Member
>> > > }
> >
> >
>> > > Shouldn't restricting access to an overriding virtual function be an
>> > > error?
> >
> > No, why? Class B could implement an interface A that is only to be
> > called directly thru the interface specification and not thru the
> > concrete implementation.
> >

Sorry but what is the definition for the word "interface".

John Lakos defined logic/physical interfaces in his "Large-Scale C++
Software Design", if we apply his definitions here, IMHO, access
specifiers should be part of the interface. So If you changed the
access specifiers, then you did change the interfaces.


>> > > After all, we can get at it anyway via an implicit conversion.
> >
> > Right, because for example B implements A, so converting B to an A 
is fine.
> >

Again, class B also changed the interface of A, and converting
B to A is fine, because now we do not have a systematical way applied
for both static and run-time checking.


>> > > Does anyone know of a legitimate design pattern that does this?
> >
> > The advantage would be that anyone using the interface described by A
> > shall not be able to use or see the extensions defined by B. You would
> > be still able to use the A interface, however very explicitly and
> > visibly in the source by turning a B into an A.
> >


Sorry I can not see the benefit here.

The private stuff should be separated in other place, change base A's
interface will bring us confusions and wont help too much here.


Goo


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Jiang 7/15/2006 9:34:13 PM

Jiang wrote:

>>>>>Shouldn't restricting access to an overriding virtual function be an
>>>>>error?
>>>
>>>No, why? Class B could implement an interface A that is only to be
>>>called directly thru the interface specification and not thru the
>>>concrete implementation.
>>>
> 
> 
> Sorry but what is the definition for the word "interface".

The definition is the standard one in software engineering: A set of 
methods provided to manipulate an entity. In C++, a class may act as an 
interface definition, often realized as a pure virtual class where the 
interface methods are given as pure virtual functions.

> John Lakos defined logic/physical interfaces in his "Large-Scale C++
> Software Design", if we apply his definitions here, IMHO, access
> specifiers should be part of the interface. So If you changed the
> access specifiers, then you did change the interfaces.

I think you're confused. The class A *defines* the interface and shall 
be visible from outside. Class B is an implementation of A hidden behind 
this interface, *not* to be used from outside and anyone else. Probably 
it acts as something else, probably it shall not be confused with the 
interface.

>>>>>After all, we can get at it anyway via an implicit conversion.
>>>
>>>Right, because for example B implements A, so converting B to an A 
> 
> is fine.
> 
> 
> Again, class B also changed the interface of A, and converting
> B to A is fine, because now we do not have a systematical way applied
> for both static and run-time checking.

In the mentioned situation, "B" does not (necessarely, at least) act as 
an interface at all. Maybe that's the source of the confusion?

>>>The advantage would be that anyone using the interface described by A
>>>shall not be able to use or see the extensions defined by B. You would
>>>be still able to use the A interface, however very explicitly and
>>>visibly in the source by turning a B into an A.

> 
> Sorry I can not see the benefit here.
> 
> The private stuff should be separated in other place, change base A's
> interface will bring us confusions and wont help too much here.

The private stuff is in "B". Class "A" ("the interface") might, for 
example, provide a default implementation that can be overriden within 
deriving implementations.

So long,
	Thomas

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Thomas 7/16/2006 12:08:16 AM

Walter Bright wrote:

> Shouldn't restricting access to an overriding virtual function be an
> error? After all, we can get at it anyway via an implicit conversion.
> Does anyone know of a legitimate design pattern that does this?

One possibility:

  struct A { virtual int foo() { return 0; } };

  class B: private A {
  private:
    int foo() { return 1; }
  public:
    // other functions use foo()
  };

Basically, we want to override a public function of a private base
class.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply johnchx2 7/16/2006 12:11:02 AM

Walter Bright wrote:
> Consider the following legal code:

> -----------------------
> #include <stdio.h>

> class A {
>    public:
>      virtual void Member() { printf("A::Member\n"); }
> };

> class B : public A {
>    private:
>      virtual void Member() { printf("B::Member\n"); }
> };

> int main()
> {
>      B *b = new B();
> //    b->Member();	// error, B::Member is private
>      A *a = b;
>      a->Member();	// calls B::Member
> }
> -------------------------

> Shouldn't restricting access to an overriding virtual function
> be an error? After all, we can get at it anyway via an
> implicit conversion.  Does anyone know of a legitimate design
> pattern that does this?

I can't think of any real use for it, but banning it introduces
a special rule, and IMHO isn't worth it.

-- 
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France +33 (0)1 30 23 00 34

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply James 7/16/2006 12:11:24 AM

Walter Bright wrote:
> Consider the following legal code:
> 
> -----------------------
> #include <stdio.h>
> 
> class A {
>    public:
>      virtual void Member() { printf("A::Member\n"); }
> };
> 
> class B : public A {
>    private:
>      virtual void Member() { printf("B::Member\n"); }
> };
> 
> int main()
> {
>      B *b = new B();
> //    b->Member();	// error, B::Member is private
>      A *a = b;
>      a->Member();	// calls B::Member
> }
> -------------------------
> 
> Shouldn't restricting access to an overriding virtual function be an 
> error? After all, we can get at it anyway via an implicit conversion. 
> Does anyone know of a legitimate design pattern that does this?

Certainly; it's a pain that Java doesn't allow this, but
that goes hand-in-hand with not allowing private derivation
from interfaces.

It's useful in C++ to be able to do

struct interface { virtual void foo() = 0; };

void use_interface(interface & i)
{
   // Code including calls via the interface...
   i.foo();
}

class concrete : private interface
{
public:
   void bar()
   {
     use_interface(*this);
   }

private:
   void foo()
   {
     std::cout << "Only accessible to selected clients.\n";
   }
};

I believe this is sometimes referred to as the "private
interface" idiom.  It can come in handy when your class
finds it appropriate to implement an interface so that
it can work with some third-party code, but does not
want to expose that interface to its own clients.

-- James

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply James 7/16/2006 2:43:49 AM

Thomas Richter wrote:
> Jiang wrote:
>
> >>>>>Shouldn't restricting access to an overriding virtual function be an
> >>>>>error?
> >>>
> >>>No, why? Class B could implement an interface A that is only to be
> >>>called directly thru the interface specification and not thru the
> >>>concrete implementation.
> >>>
> >
> >
> > Sorry but what is the definition for the word "interface".
>
> The definition is the standard one in software engineering: A set of
> methods provided to manipulate an entity. In C++, a class may act as an
> interface definition, often realized as a pure virtual class where the
> interface methods are given as pure virtual functions.
>


Thanks for the explanation, now I see your point and we do share the
same idea that a class may act as an interface definition.

Actually I am not confused by making virtual functions private, I
just can not understand the rationale of allowing access specifiers
changing in derived classes.


> > John Lakos defined logic/physical interfaces in his "Large-Scale C++
> > Software Design", if we apply his definitions here, IMHO, access
> > specifiers should be part of the interface. So If you changed the
> > access specifiers, then you did change the interfaces.
>
> I think you're confused. The class A *defines* the interface and shall
> be visible from outside. Class B is an implementation of A hidden behind
> this interface, *not* to be used from outside and anyone else. Probably
> it acts as something else, probably it shall not be confused with the
> interface.
>


1. From your definition, I see that usually every class has an
   interface, no matter it is a base class or derived class.
   Here if B->A is merely an relationship of "implementation-of",
   then the interface (under your definition) defined in A should
   be *respected* in B.

2. And from my limited c++ knowledge, B->A should be a relationship
   of "is-a". that is, for the following example,

      class A{
          public:
          // non-virtual but perfect interface definition
          void bar(){
            // A's implementation
          }
      };

      class B : public A{
          private:
          void bar(){
            // B's implementation
          }
      };

   B should not be considered as an A, since it can not expose the
   necessary interface now. Removing the virtual declaration makes my
   point a little bit clear in my mind.

   Maybe it is just a problem of wording, but it is quite confusing.

3. It is true that usually virtual functions should work in a
   polymorphic manner, but it is possible (quite often?) that the
   virtual functions are called statically. The OP showed an example.
   That means, sometimes we just want to use B's interface only, and
   dynamic binding is disabled intentionally. Well, the design is maybe
   not flawless, but I must say it happens in the real-world.




> >>>>>After all, we can get at it anyway via an implicit conversion.
> >>>
> >>>Right, because for example B implements A, so converting B to an A
> >
> > is fine.
> >
> >
> > Again, class B also changed the interface of A, and converting
> > B to A is fine, because now we do not have a systematical way applied
> > for both static and run-time checking.
>
> In the mentioned situation, "B" does not (necessarely, at least) act as
> an interface at all. Maybe that's the source of the confusion?
>

Yes, that's the problem.

I thought/think B has its own interface, partly derived from A, partly
defined by itself. The later one causes compile error for OP's first
usage.

> >>>The advantage would be that anyone using the interface described by A
> >>>shall not be able to use or see the extensions defined by B. You would
> >>>be still able to use the A interface, however very explicitly and
> >>>visibly in the source by turning a B into an A.
>
> >
> > Sorry I can not see the benefit here.
> >
> > The private stuff should be separated in other place, change base A's
> > interface will bring us confusions and wont help too much here.
>
> The private stuff is in "B". Class "A" ("the interface") might, for
> example, provide a default implementation that can be overriden within
> deriving implementations.
>


As I said before, I see the point here.

However, compared with changing access specifiers in derived class,
Template Method, or the Nonvirtual Interface Pattern (NVI) is much
clean and controllable/understandable in my mind.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Jiang 7/16/2006 12:38:03 PM

Walter Bright wrote:

> #include <stdio.h>
>
> class A {
>    public:
>      virtual void Member() { printf("A::Member\n"); }
> };
>
> class B : public A {
>    private:
>      virtual void Member() { printf("B::Member\n"); }
> };
>
> int main()
> {
>      B *b = new B();
> //    b->Member();	// error, B::Member is private
>      A *a = b;
>      a->Member();	// calls B::Member
> }
> -------------------------
>
> Shouldn't restricting access to an overriding virtual function be an
> error? After all, we can get at it anyway via an implicit conversion.
> Does anyone know of a legitimate design pattern that does this?

I can't believe that this question still pops up after all these years 
of having been beaten to death. Googling for "private interface" should 
yield convincing arguments for why keeping virtual dispatch and access 
level orthogonal is desirable.

-- 
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address 
with "kapsch" and the top level domain part with "net".

The information contained in this e-mail message is privileged and
confidential and is for the exclusive use of the addressee. The person
who receives this message and who is not the addressee, one of his
employees or an agent entitled to hand it over to the addressee, is
informed that he may not use, disclose or reproduce the contents thereof.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Gerhard 7/17/2006 8:04:25 PM

johnchx2@yahoo.com wrote:
> Walter Bright wrote:
>> Shouldn't restricting access to an overriding virtual function be an
>> error? After all, we can get at it anyway via an implicit conversion.
>> Does anyone know of a legitimate design pattern that does this?
> 
> One possibility:
> 
>   struct A { virtual int foo() { return 0; } };
> 
>   class B: private A {
>   private:
>     int foo() { return 1; }
>   public:
>     // other functions use foo()
>   };
> 
> Basically, we want to override a public function of a private base
> class.

Hmmm, for a base-class, two access-specifiers are effective, one being the
one for the baseclass itself and one being the one for the particular
element thereof. The result of these two stages is always the most
restrictive access-specifier.
This means two things:
1. Your example is bad because access to A::foo() is already private
because access to A is private.
2. Your example is good because it shows a typical and common case where
the access to the baseclass' members via the derived class is different
from the direct access.

That said, changing access in a way that is not enforced by the compiler
and which might even give people a false feeling of security is a nono.
I'd call it worth a warning by a good compiler. OTOH, others even
presented this as idiomatic, so I don't think that will happen.

Uli



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Ulrich 7/17/2006 8:05:25 PM

Walter Bright wrote:
> Consider the following legal code:
>
> -----------------------
> #include <stdio.h>
>
> class A {
>    public:
>      virtual void Member() { printf("A::Member\n"); }
> };
>
> class B : public A {
>    private:
>      virtual void Member() { printf("B::Member\n"); }
> };
>
> int main()
> {
>      B *b = new B();
> //    b->Member();	// error, B::Member is private
>      A *a = b;
>      a->Member();	// calls B::Member
> }
> -------------------------
>
> Shouldn't restricting access to an overriding virtual function be an
> error?

No, because there is a difference between invoking a method and
executing a method. Access levels can prohibit the invocation of a
class method outside of certain program contexts - but they have
nothing to do with prohibiting a method's execution at all. Nor would
prohibiting a method's execution really make much sense as a concept -
since every method has to be able to execute at some point (otherwise,
why would the method exist in the first place?). So what would it mean
to prohibit a method's execution only some of the time? How could that
notion be formalized and why would it be useful?

In reality, a class method cannot safely make any assumptions about its
caller - it can only make assumptions about the state of its class
object at the point it begins its execution. In other words, a class
method can count on its necessary preconditions having been met before
it is called, the called method just cannot assume that some other
particular function was the one that called it (though often that
information can be deduced if only one other routine can fulfill its
necessary preconditions).

The example program above shows nothing more than this method
invocation vs. execution distinction. The program contrives to execute
B::Member but does not do so by invoking B::Member itself. And while it
may not make much sense to use access levels in this manner, there is
no reason to make this use illegal - since nothing about the program
should be surprising.

Greg


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Greg 7/17/2006 8:10:36 PM

Walter Bright wrote:
> Consider the following legal code:

> Shouldn't restricting access to an overriding virtual function be an
> error? After all, we can get at it anyway via an implicit conversion.
> Does anyone know of a legitimate design pattern that does this?

Maybe template method combined with factory method:

namespace ns{
class ClientServiceIf
{
  public:
    virtual void doX();
    virtual void doY();
    virtual void doZ();
};
class Client
{
  public:
    void processXYZ();

  private:
    virtual ClientServiceIf* makeService() const;
    boost::scoped_ptr<ClientServiceIf> service_; //initialised by
makeService...
};

}//ns

//cpp
namespace ns{
void Client::processXYZ()
{
  service_->doX();
  service_->doY();
  service_->doZ();
}
}

Couple of things one can note here:

1) We want to promote usage through interface/abc only.
2) We intend to provide the extension of the interface ourselves, and
have no desire for the client to even know that the type of the
extension exists. For this reason, why not make the member functions
private, as they simply don't need to be public. This makes the intent
of the implementor clearer (IMHO).

There are of course other ways in which this cat can be skinned - for
example:

class Service: private ClientServiceIf
{
public:
  static ClientServiceIf* make(){ return new Service(); }
  ~Service();

private: //all the rest
  Service();
  virtual void doX(); //etc
};

Here again (more explicitly) we can only use this class via the base
interface. The derived only holds the (is the) implementation. A user
would have to cast to the derived explicitly if he were to change the
order of calling XYZ, in which case he has brought erroneous behaviour
upon himself - so to speak.

Regards.

Werner


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply werasm 7/17/2006 8:12:00 PM

werasm wrote:
> Walter Bright wrote:

> class Service: private ClientServiceIf
> {
> public:
>   static ClientServiceIf* make(){ return new Service(); }
>   ~Service();
>
> private: //all the rest
>   Service();
>   virtual void doX(); //etc
> };

Actually, I omitted that this class could only be destructed through
base as well. Therefore destructor of Service should be private too,
and ClientServiceIf should have public virtual destructor.

Regards,

Werner


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply werasm 7/18/2006 1:45:40 PM

Ulrich Eckhardt wrote:
> johnchx2@yahoo.com wrote:
> > Walter Bright wrote:
> >> Shouldn't restricting access to an overriding virtual
> >> function be an error? After all, we can get at it anyway
> >> via an implicit conversion.  Does anyone know of a
> >> legitimate design pattern that does this?

> > One possibility:

> >   struct A { virtual int foo() { return 0; } };

> >   class B: private A {
> >   private:
> >     int foo() { return 1; }
> >   public:
> >     // other functions use foo()
> >   };

> > Basically, we want to override a public function of a
> > private base class.

> Hmmm, for a base-class, two access-specifiers are effective,
> one being the one for the baseclass itself and one being the
> one for the particular element thereof. The result of these
> two stages is always the most restrictive access-specifier.

That's true for the members of A.  B::foo() isn't a member of A;
it's a member of B.  The question was why allow B::foo() to be
private when A::foo() is public.

> This means two things:
> 1. Your example is bad because access to A::foo() is already private
> because access to A is private.

A::foo() isn't private to anyone who has an A*.  And of course,
however calls A::foo() actually ends up in B::foo().  The
reasoning was that it makes no sense to make B::foo() private,
because anyone with a B* can access it as public by converting
the B* to an A*.  The counter-example is, of course, when the
inheritance is private: someone with a B* here cannot get the A*
necessary to access it, so the function is private to such
users.

> 2. Your example is good because it shows a typical and common
> case where the access to the baseclass' members via the
> derived class is different from the direct access.

> That said, changing access in a way that is not enforced by
> the compiler and which might even give people a false feeling
> of security is a nono.  I'd call it worth a warning by a good
> compiler. OTOH, others even presented this as idiomatic, so I
> don't think that will happen.

I think the case probably most often occurs when A is some sort
of callback interface.  Some member function of B registers the
object for the callback.  (A member fucntion of B can convert
the B* this pointer to an A*.)  No other user ever sees an A*.
Nor can it: because derivation is private, the conversion B* to
A* is illegal.

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 7/18/2006 10:59:48 PM

In article news:<1153146840.257909.293230@i42g2000cwa.googlegroups.com>, 
Greg Herlihy wrote:
> > Shouldn't restricting access to an overriding virtual function be an
> > error?
> 
> No, because there is a difference between invoking a method and
> executing a method.

That's a pretty fine distinction -- and one that many users find confusing. 
I'm not sure that it is helpful to make that distinction at all ...

> Access levels can prohibit the invocation of a class method outside of
> certain program contexts - but they have nothing to do with prohibiting
> a method's execution at all.

No, indeed. In Walter's example there's nothing to stop the client making 
the call as 
  
  reinterpret_cast<A*>(b)->Member();
  
so I can see very little benefit in making B::Member private, or in 
allowing it to be made so.

If the intention is to enforce a polymorphic interface callable only* 
through the base class there are more rigid ways of doing so:

-----------------------
#include <stdio.h>

class A {
   public:
     void Member() { DoMemberStuff(); }
   private:
     virtual void DoMemberStuff() { printf("A::DoMemberStuff\n"); }
};

class B : public A {
   private:
     virtual void DoMemberStuff() { printf("B::DoMemberStuff\n"); }
};

int main()
{
     A *a = new A();
     a->Member(); // OK, A::Member calls A::DoMemberStuff
     B *b = new B();
     b->Member(); // OK, A::Member calls B::DoMemberStuff
     A *a2 = b;
     a2->Member(); // OK, A::Member calls B::DoMemberStuff
}
-------------------------

Now there is no confusion. The public interface in A is public and can be 
called with the desired effect on objects of either type A or type B; the 
internal implementation is polymorphic because DoMemberStuff is virtual, 
and is private (in both classes) which is both appropriate and consistent.

I can't immediately think of any reason not to do it this way, in real code 
(I realize that Walter's snippet was just an example to expose this quirk 
of the language).

> The example program above shows nothing more than this method
> invocation vs. execution distinction. The program contrives to execute
> B::Member but does not do so by invoking B::Member itself. And while it
> may not make much sense to use access levels in this manner, there is
> no reason to make this use illegal - since nothing about the program
> should be surprising.

I would say that the thing that most often surprises people is that marking 
a virtual function private does not make it private in any real sense if it 
is marked public elsewhere. It seems a pretty reasonable idea to make this 
illegal (though I'm not sure it's worth the angst and upheaval of a 
language change).

While we're on the subject: in Walter's example B::Member does not need to 
be marked virtual -- it is implicitly virtual because it overrides a 
virtual function in A. This can also cause confusion in much the same way 
as differences in public/private declaration: people declare what they 
think is a non-virtual function that is in fact virtual because it 
overrides a virtual function in the parent class. I would favour requiring 
the declaration of the override in the derived class to explicitly match 
the declaration of the parent function that it overrides in terms of 
virtualness and access type (public/private/protected).
-- 
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 7/18/2006 11:03:29 PM

Daniel James wrote:

> If the intention is to enforce a polymorphic interface callable only*
> through the base class there are more rigid ways of doing so:
>
> -----------------------
> #include <stdio.h>
>
> class A {
>    public:
>      void Member() { DoMemberStuff(); }
>    private:
>      virtual void DoMemberStuff() { printf("A::DoMemberStuff\n"); }
> };
>
> class B : public A {
>    private:
>      virtual void DoMemberStuff() { printf("B::DoMemberStuff\n"); }
> };
>
> int main()
> {
>      A *a = new A();
>      a->Member(); // OK, A::Member calls A::DoMemberStuff
>      B *b = new B();
>      b->Member(); // OK, A::Member calls B::DoMemberStuff
>      A *a2 = b;
>      a2->Member(); // OK, A::Member calls B::DoMemberStuff
> }
> -------------------------
>
> Now there is no confusion. The public interface in A is public and can
> be called with the desired effect on objects of either type A or type
> B; the internal implementation is polymorphic because DoMemberStuff is
> virtual, and is private (in both classes) which is both appropriate
> and consistent.
>
> I can't immediately think of any reason not to do it this way, in real
> code (I realize that Walter's snippet was just an example to expose
> this quirk of the language).

I can think of a good reason: it is unnecessarily verbose and adds 
cruft. You get no additional functionality for three times as much code. 
Why should you mess around manually with copy and paste and regular 
expressions when the language offers an automated, idiomatic way (which 
you call a quirk)?

Template Method is a valuable pattern when the template method does some 
processing of its own, such as implementing Design by Contract. For 
simple callback interfaces, as in Observer, this is typically not 
needed, and maintaining do-nothing wrappers just for the sake of 
rigidity and not confusing Java programmers would be grotesque.

It is ironic that languages which do not allow changing the access 
level, such as Java and C#, also prohibit implementation in interfaces, 
which renders the solution you advocate impossible.

-- 
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address 
with "kapsch" and the top level domain part with "net".

The information contained in this e-mail message is privileged and
confidential and is for the exclusive use of the addressee. The person
who receives this message and who is not the addressee, one of his
employees or an agent entitled to hand it over to the addressee, is
informed that he may not use, disclose or reproduce the contents thereof.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Gerhard 7/19/2006 10:37:34 PM

Daniel James wrote:
> In article
> news:<1153146840.257909.293230@i42g2000cwa.googlegroups.com>,
> Greg Herlihy wrote:

    [...]
> > Access levels can prohibit the invocation of a class method
> > outside of certain program contexts - but they have nothing
> > to do with prohibiting a method's execution at all.

> No, indeed. In Walter's example there's nothing to stop the
> client making the call as

>   reinterpret_cast<A*>(b)->Member();

You mean static_cast, I think.  Reinterpret_cast has undefined
behavior here.

> so I can see very little benefit in making B::Member private,
> or in allowing it to be made so.

In Walter's example, that's true.  As others have pointed out,
if the inheritance is private, static_cast will not allow you to
get the A*, so the function really is private.  Except to
clients whom the B* has given an A*.

    [...]
> While we're on the subject: in Walter's example B::Member does
> not need to be marked virtual -- it is implicitly virtual
> because it overrides a virtual function in A. This can also
> cause confusion in much the same way as differences in
> public/private declaration: people declare what they think is
> a non-virtual function that is in fact virtual because it
> overrides a virtual function in the parent class. I would
> favour requiring the declaration of the override in the
> derived class to explicitly match the declaration of the
> parent function that it overrides in terms of virtualness and
> access type (public/private/protected).

Ideally, I'd like to distinguish between 1) functions which are
not virtual, 2) virtual functions which are at the bottom of the
hierarchy, i.e. that don't override anything, and 3) functions
which override a virtual function at a lower lever---in fact, in
3, it would also be nice to be able specify whether the function
can be further overriden or not.  Obviously, because of history,
this can no longer be done.  But even starting from scratch,
there is a question as to how much the added complexity costs as
opposed to the benefits of more precise specification.

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 7/19/2006 10:40:29 PM

In article news:<44bde91b$1@news.kapsch.co.at>, Gerhard Menzl wrote:
> ... it is unnecessarily verbose and adds cruft. You get no additional
> functionality for three times as much code.

Three methods where previously there were two is not "three times as much".

Any "cruft" will be optimized away by a decent compiler .

> Why should you mess around manually with copy and paste and regular 
> expressions when the language offers an automated, idiomatic way (which 
> you call a quirk)?

Copy? Regular expressions? I see neither of those in evidence here.

The trouble is that what you call an "automated idiomatic way" does not, in 
fact, work [1] and is confusing (especially to the newcomer to C++). The 
code I presented is easier to follow and achieves the effect we've been 
discussing (that B::DoMemberStuff cannot be invoked other than virtually 
via an A object) reliably.

I think it is worth the extra line or two of code to make the intent of the 
source clearer to the reader (read: maintenance programmer).

[1] Given that B inherits publicly from A -- as in Walter's example which I 
have taken at face value. In "real code" it might or might not be possible 
to change the inheritance to private.

-- 
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 7/20/2006 9:40:00 PM

Gerhard Menzl wrote:

    [...]
> Template Method is a valuable pattern when the template method
> does some processing of its own, such as implementing Design
> by Contract. For simple callback interfaces, as in Observer,
> this is typically not needed, and maintaining do-nothing
> wrappers just for the sake of rigidity and not confusing Java
> programmers would be grotesque.

First a nit: design by contract is not the template pattern.  In
C++, the two look superficially alike, since they are based on
the same language feature, but the intent is different, and the
implementations look different in other languages (and may look
different in a future version of C++).

And of course, there are cases where you have no contract; in
such cases, using the design by contract pattern to enforce
something that isn't there by design is just silly (which is
basically what you are saying).  Typically, this is the case
with various notifications, callbacks and what have you's.  (I
believe the Kevlin Henney calls this inversion of control flow.
Basically, it occurs when the reason someone is calling you is
because you asked him to.)

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 7/20/2006 9:40:30 PM

In article news:<1153300320.916748.205780@m79g2000cwm.googlegroups.com>, 
Kanze wrote:
> >   reinterpret_cast<A*>(b)->Member();
> 
> You mean static_cast, I think.  Reinterpret_cast has undefined
> behavior here.

Apologies: I mean dynamic_cast.

> > While we're on the subject: ...
[snip]
> 
> Ideally, I'd like to distinguish between 1) functions which are
> not virtual, 2) virtual functions which are at the bottom of the
> hierarchy, i.e. that don't override anything, and 3) functions
> which override a virtual function at a lower lever---in fact, in
> 3, it would also be nice to be able specify whether the function
> can be further overriden or not.

I agree. It's a not-uncommon error to add a method to a derived class 
without realizing that it overrides an existing (but possibly undocumented) 
method in a parent class, and it can cause strange behaviour (with no 
compile-time diagnostic) that is hard to diagnose. Source-code 
specifications such as you suggest would help to eliminate these errors.

> Obviously, because of history, this can no longer be done.

It could be added as an optional feature (rather as 'const' was added to C, 
post-K&R) but would be of limited use until widely adopted.

> ... even starting from scratch, there is a question as to how much the
> added complexity costs as opposed to the benefits of more precise
> specification.

Agreed.

-- 
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 7/20/2006 9:41:06 PM

walter@digitalmars-nospamm.com (Walter Bright) wrote (abridged):
> Shouldn't restricting access to an overriding virtual function be an 
> error? After all, we can get at it anyway via an implicit conversion.

What would be gained by making it an error?


> Does anyone know of a legitimate design pattern that does this?

The closest I have seen is where the derived class needs to provide the 
base class interface, but discourages its use in favour of a new interface 
of its own.

    class Version_1 {
    public:
        virtual void slowFunc();
    };
    
    class Version_2 : public Version_1 {
    public:
        virtual void fastFunc(); // Like slowFunc() but faster.
    private:
        virtual void slowFunc(); // Now depreciated.
    };

Here Version_1 is an old, obsolete interface, and Version_2 is the new 
improved one. All objects that support Version_2 also support Version_1, 
and there is an implicit conversion to make passing the new objects to old 
routines convenient. However, new routines are strongly encouraged to use 
the new interface.

    void newRoutine( Version_2 &object ) {
        // object.slowFunc(); // Error.
        Version_1 &old = object;
        old.slowFunc(); // OK but depreciated.
        object.fastFunc(); // Preferred.
    }

So far as I know this hasn't been written up as a design pattern, and I 
don't know if you'd consider it legitimate if it was. The question is 
whether we would be better off if it were forbidden at the language level.

-- Dave Harris, Nottingham, UK.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply brangdon 7/22/2006 6:16:55 PM

Daniel James wrote:

> Three methods where previously there were two is not "three times as
> much".

Two methods instead of one, plus the extra invocation of the virtual
function in the non-virtual function, yields - roughly - three times as
much code.

> Any "cruft" will be optimized away by a decent compiler .

I don't care what the compiled code looks like, I am talking about
source code cruft, which remains to annoy the human reader.

> Copy? Regular expressions? I see neither of those in evidence here.

Of course you can tackle the resulting code triplication by typing
everything manually. Since the declaration of the virtual function is
typically identical to that of the non-virtual function, except for the
virtual keyword and the Do prefix, most people would use some sort of
automation: dumb ones like copy, paste, edit, or smarter ones, such as
regular expressions. Code generators that perform the task automatically
may exist but are far from being mainstream.

> The trouble is that what you call an "automated idiomatic way" does
> not, in fact, work [1] and is confusing (especially to the newcomer to
> C++). The code I presented is easier to follow and achieves the effect
> we've been discussing (that B::DoMemberStuff cannot be invoked other
> than virtually via an A object) reliably.

I don't know what you mean by "does not, in fact, work". Private
Interface typically uses private inheritance and works like a charm. If
you were to ban all language features that are confusing to newcomers,
there would not be much language left to use. Every programming
languages has its idioms, and this is one of them.


--  
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".

The information contained in this e-mail message is privileged and
confidential and is for the exclusive use of the addressee. The person
who receives this message and who is not the addressee, one of his
employees or an agent entitled to hand it over to the addressee, is
informed that he may not use, disclose or reproduce the contents  
thereof.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Gerhard 7/24/2006 6:09:17 PM

In article news:<44c4ddbd$1@news.kapsch.co.at>, Gerhard Menzl wrote:
> > Two methods instead of one, plus the extra invocation of the virtual
> > function in the non-virtual function, yields - roughly - three times as
> > much code.

Er ... it's just one extra line.

> > I don't care what the compiled code looks like, I am talking about
> > source code cruft, which remains to annoy the human reader.

We're just going to have to agree to disagree on that. I don't see any
cruft there, and I certainly don't find the code annoying - to my eyes 
it looks better structured.

There's a concrete advantage in having a single non-virtual base-class
interface that uses (private) virtual dispatch internally: you have a
single entry point at which you can test preconditions and 
postconditions, place break points, log, and suchlike.

> > I don't know what you mean by "does not, in fact, work". Private
> > Interface typically uses private inheritance and works like a charm.

I did state explicitly that I was taking the example at face value and
discussing the situation with public inheritance. In that case 
downcasting to the base class is always possible so nothing is gained by 
making B::Member (in the original code) private.

I agree that things are different with private inheritance.

I still don't see that there's any need to allow A::Member and B::Member 
to have different access specifiers ... is there any real code in which 
that can be useful?

> > If you were to ban all language features that are confusing to 
newcomers,
> > there would not be much language left to use.

That's very true, but where there are multiple ways to achieve the same 
end and one is confusing but the others are not I see no problem in 
forbidding the use of the confusing one.

> > Every programming languages has its idioms, and this is one of them.

More of a quirk than an idiom.

--
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 7/25/2006 1:56:53 PM

Daniel James wrote:

> In article news:<44c4ddbd$1@news.kapsch.co.at>, Gerhard Menzl wrote:
>>> Two methods instead of one, plus the extra invocation of the virtual
>>> function in the non-virtual function, yields - roughly - three times
>>> as much code.
>
> Er ... it's just one extra line.

Who said anything about lines? I said it's three times as much code. 
Three times as much to review and to maintain, three times as many 
opportunities to introduce errors.

> We're just going to have to agree to disagree on that. I don't see any
> cruft there, and I certainly don't find the code annoying - to my eyes
> it looks better structured.

If your idea of better structure is to write explicitly what is built 
into the language, then yes, we'll have to aagree to disagree.

> I did state explicitly that I was taking the example at face value and
> discussing the situation with public inheritance. In that case
> downcasting to the base class is always possible so nothing is gained
> by making B::Member (in the original code) private.

While I agree that the situation with public inheritance is different, 
and changing access levels is more questionable, I don't think that 
nothing is gained. Users of B would have to circumvent the barrier 
deliberately, which is not the same as just calling the member by accident.

> I agree that things are different with private inheritance.
>
> I still don't see that there's any need to allow A::Member and
> B::Member to have different access specifiers ... is there any real
> code in which that can be useful?

Simple private callback interfaces. Observer pattern. A pain to 
implement in Java or C#.

> More of a quirk than an idiom.

It is in the tradition of not preventing the programmer from shooting 
himself in the foot. This allows some questionable constructs, but at 
the same time concise and elegant solutions that are impossible in other 
languages. If you dismiss these as quirks, then ... (see above).

-- 
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address 
with "kapsch" and the top level domain part with "net".

{sig trimmed. -mod}

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Gerhard 7/26/2006 3:11:31 PM

Gerhard Menzl wrote:
> Who said anything about lines? I said it's three times as much code.
> Three times as much to review and to maintain, three times as many
> opportunities to introduce errors.
>

I think it's easier to maintain code that is obvious and
understandable, even if a little longer (much like Ruby being easier
than Perl to review). I also think it's easier to introduce errors into
code that's not as understandable and doesn't work like one would
expect.

> Simple private callback interfaces. Observer pattern. A pain to
> implement in Java or C#.
>

I don't get this, the observer pattern isn't difficult to implement in
C#
http://dofactory.com/Patterns/PatternObserver.aspx

I'd be interested to hear why this is considered difficult though.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply shadow 7/26/2006 4:10:32 PM

In article news:<44c77720$1@news.kapsch.co.at>, Gerhard Menzl wrote:
> > Er ... it's just one extra line.
> 
> Who said anything about lines?

You did. You wrote:

> I don't care what the compiled code looks like, I am talking about
> source code cruft, ...

Admittedly you said that in the next sentence, but I think I may be forgiven

for interpreting that as a general remark.

> I said it's three times as much code. 

It isn't. It's one non-virtual and two virtual functions with the same
access 
type where previously there were two virtual functions with different access

types. As the non-virtual function is likely to be optimized away it's 
probably the same amount of code.

> Three times as much to review and to maintain, three times as many
> opportunities to introduce errors.

Now you're talking about source again ... I would say that the code in which

Member has different access types in the two classes is less 'obvious': we 
all know what it means and what it does, but it has to be thought about
more, 
and so more requires more effort from the maintenance programmer, and so is 
more likely to engender bugs.

> > We're just going to have to agree to disagree on that. I don't see any
> > cruft there, and I certainly don't find the code annoying - to my eyes
> > it looks better structured.
> 
> If your idea of better structure is to write explicitly what is built 
> into the language, then yes, we'll have to aagree to disagree.

What is being made explicit is the separation between interface and 
implementation. I'd call that "documentation". Couple that with the 
advantages of having a single point of entry for debugging, logging, etc., 
that I mentioned in my last posting and to which you have made no reference
I 
would say that making it explicit is advantageous.

> Users of B would have to circumvent the barrier deliberately, which is not
> the same as just calling the member by accident.

True ... but users will be users.

> > I still don't see that there's any need to allow A::Member and
> > B::Member to have different access specifiers ... is there any real
> > code in which that can be useful?
> 
> Simple private callback interfaces. Observer pattern. A pain to 
> implement in Java or C#.

Perhaps I'm being stupid (it's the heat) but I don't see what you're getting

at -- how does it help to change the access type of a virtual function
within 
the class hierarchy in these cases? What does it enable you to achieve that 
couldn't be achieved if this (to my eyes) rather dirty trick were not 
allowed?

I've written callbacks and observers without using it, and not been aware of

any particular difficulty, so please enlighten me!

> > More of a quirk than an idiom.
> 
> It is in the tradition of not preventing the programmer from shooting 
> himself in the foot.

It looks to me more like giving the programmer feet he didn't know he had, 
and putting them directly in front of his gun <smile>

Cheers,
 Daniel.
 




-- 
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 7/27/2006 1:26:02 PM

shadow wrote:

> Gerhard Menzl wrote:
>> Simple private callback interfaces. Observer pattern. A pain to
>> implement in Java or C#.
>>
>
> I don't get this, the observer pattern isn't difficult to implement in
> C#
> http://dofactory.com/Patterns/PatternObserver.aspx
>
> I'd be interested to hear why this is considered difficult though.

Because C#, like Java, which it was designed to compete with, forces you 
to make the overridden version of Update() public. But if I register a 
concrete Observer with a Subject, I don't necessarily want other clients 
to be able to fake Update() calls. I want the Subject, and no-one but 
the Subject, to call Update(). In C++, I derive privately from Observer 
and change the access level to private. C# and Java do not allow this; 
at the same time, they also prevent me from choosing the other possible 
(and more awkward) implementation:

   interface Observer
   {
     public void Update() { doUpdate() };  // error: no implementation
                                           // in interfaces
     private abstract void doUpdate();
   }

unless you make Observer a class (as in the sample code you referred to) 
- which limits you to single inheritance. This is a royal pain. I wonder 
whether delegates were invented because callback interfaces are so 
awkward to implement.

-- 
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address 
with "kapsch" and the top level domain part with "net".

{sig trimmed. -mod}


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Gerhard 7/27/2006 1:28:39 PM

Daniel James wrote:
> In article news:<1153146840.257909.293230@i42g2000cwa.googlegroups.com>,
> Greg Herlihy wrote:
> > > Shouldn't restricting access to an overriding virtual function be an
> > > error?
> >
> > No, because there is a difference between invoking a method and
> > executing a method.
>
> That's a pretty fine distinction -- and one that many users find
confusing.
> I'm not sure that it is helpful to make that distinction at all ...

The distinction between method invocation and method execution is
crucial for any understanding of what a virtual method is. Because
unlike a call to a non-virtual method - which always executes the same
method no matter how many times it is called - a call to a virtual
method can execute one of any number of different methods and the
method executed can vary from one call to the next - depending on the
runtime type of the object whose method is being invoked.

A C++ programmer therefore knows that there is a loose connection
between calling a virtual method and executing one. And all that the
the original program really demonstrated was that it is possible for a
program to bind a particular method invocation with a particular
method's execution - even though there was little apparent reason this
particular connection would ever be useful.

But simply because a particular application of a feature seems useless,
is not sufficient grounds to ban that application. After all, it makes
little sense to define a constant integer value as 1+1, so should the
1+1 form be made illegal?

The answer is no. Because 1+1 abides by the rules for expressions - and
not all expressions need to be useful - only some of them need to have
value in order to justify the existence of the entire set. Just as not
all method invocation/method execution pairings need to be useful to a
program - as long as some of the pairings are useful there is
justification enough to allow all of them.

Greg


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Greg 7/27/2006 2:58:32 PM

Daniel James wrote:

> In article news:<44c77720$1@news.kapsch.co.at>, Gerhard Menzl wrote:
>>> Er ... it's just one extra line.
>> Who said anything about lines?
>
> You did. You wrote:
>
>> I don't care what the compiled code looks like, I am talking about
>> source code cruft, ...

This is getting a bit silly, I'm afraid, but I don't see lines mentioned 
anywhere in there.

You advocate replacing:

    class Callback
    {
    public:
       virtual void CallMeBack (CallbackData d, Parameter p) = 0;
    };

with:

    class Callback
    {
    public:
       void CallMeBack (CallbackData data, ExtraParameter expar)
       {
          this->DoCallMeBack (data, expar);
       }

    private:
       virtual void DoCallMeBack (CallbackData d, Parameter p) = 0;
    };

So you get two function declarations and one function invocation for one 
function declaration. Every parameter appears three times instead of 
once. That's a factor of 3 : 1. I don't care what the respective numbers 
of lines are, it's three times as much code that has to be maintained.

I concede that if you take derived classes into account, the overall 
ratio will be lower, but the interface class is blown up by a factor of 
three.

> Now you're talking about source again ...

I am talking about source code all the time.

> I would say that the code in which Member has different access types
> in the two classes is less 'obvious': we all know what it means and
> what it does, but it has to be thought about more, and so more
> requires more effort from the maintenance programmer, and so is more
> likely to engender bugs.

It is in the nature of idioms that they have to be thought about *less*, 
and that they are *less* likely to engender bugs, providing they are 
applied correctly, of course.

> What is being made explicit is the separation between interface and
> implementation. I'd call that "documentation". Couple that with the
> advantages of having a single point of entry for debugging, logging,
> etc., that I mentioned in my last posting and to which you have made
> no reference I would say that making it explicit is advantageous.

The separation of interface and implementation is made explicit and 
documented sufficiently by the existence of an abstract base class and a 
concrete class derived from it. Any programmer vaguely familiar with 
object-oriented design and design patterns will recognize this instantly.

I don't see what "a single point of entry for debugging" buys you. I 
have never found the need for regularly breaking execution at every 
virtual function call. If you need to log in the base class, then, of 
course, it ceases to be a mere abstract interface, and hiding the 
virtual function behind a public non-virtual function is justified, just 
as it is with precondition checks. But logging is part of the design, 
not something that you add willy-nilly.

> Perhaps I'm being stupid (it's the heat) but I don't see what you're
> getting at -- how does it help to change the access type of a virtual
> function within the class hierarchy in these cases? What does it
> enable you to achieve that couldn't be achieved if this (to my eyes)
> rather dirty trick were not allowed?
>
> I've written callbacks and observers without using it, and not been
> aware of any particular difficulty, so please enlighten me!

    // code that does nothing to illustrate the point, such as
    // constructors, destructors, error handling, etc. omitted

    class NetworkObserver
    {
    public:
       virtual void HandleNetworkEvent(NetworkEvent* event) = 0;
    };

    class NetworkDispatcher
    {
    public:
       static NetworkDispatcher& Instance();

       void Register(NetworkObserver* observer, int portno);
       void Unregister(NetworkObserver* observer);

       // private implementation details here
    };

Now suppose you want to design a class that needs to react to network 
events on a particular port to fulfill its role. Let's call it 
Communicator for want of a better example. Communicator derives from 
NetworkObserver, overrides HandleNetworkEvent(), and registers with the 
NetworkDispatcher. If you keep the original access level, 
HandleNetworkEvent() becomes part of the public interface of 
Communicator. Every client may call it. But of course that is not what 
you want. If HandleNetworkEvent() is called, you want to be sure it's 
called by the NetworkDispatcher (or one of its subcontractors), and 
nobody else. By making it public you would convey a false message to 
clients. They are not meant to call you back, so they should not be 
allowed to. In C++, you can solve this elegantly:

    class Communicator : private NetworkObserver
    {
    public:
       void Start()
       {
          NetworkDispatcher::Instance().Register (this, ourPort);
       }

       void Stop()
       {
          NetworkDispatcher::Instance().Unregister (this);
       }

       // rest of public interface

    private:
       virtual void HandleNetworkEvent(NetworkEvent* event)
       {
          // do whatever you need to do in response
       }

       static int const ourPort = 10000;
    };

Inflating NetworkObserver in your preferred way buys you nothing. No 
need for logging, no precondition checking - it's a simple callback 
interface. Note that languages like Java and C#, which do not allow you 
to change access levels in derived classes, also make it impossible to 
wrap the virtual function call in the base class in a non-virtual 
function, unless you restrict yourself to single inheritance (i.e. never 
terminate more than one protocol). So much for protecting developers 
from themselves.

> It looks to me more like giving the programmer feet he didn't know he
> had, and putting them directly in front of his gun <smile>

C++ has a number of quirks that meet your metaphoric description, such as

    Class object();

being parsed as a function declaration, or

    template <typename Container = std::vector<int>>

as a bit shift to the right. I don't think the orthogonality of access 
level and overriding belongs in this category. Access level governs who 
is allowed to call a function or access a variable. It does not affect 
overriding. While it may surprise people, it's conceptually clean and 
consistent. That many C++ programmers are not familiar enough with the 
language to be aware of this does not qualify it as a dirty quirk.


-- 
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address 
with "kapsch" and the top level domain part with "net".

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Gerhard 7/28/2006 11:58:44 AM

In article news:<1154011341.612365.264030@m73g2000cwd.googlegroups.com>,
Greg Herlihy wrote:
> > Greg Herlihy wrote:
> > > No, because there is a difference between invoking a method and
> > > executing a method.
> [I wrote]
> > That's a pretty fine distinction -- and one that many users find
> > confusing.
> > I'm not sure that it is helpful to make that distinction at all ...
>
> The distinction between method invocation and method execution is
> crucial for any understanding of what a virtual method is. Because
> unlike a call to a non-virtual method - which always executes the same
> method no matter how many times it is called - a call to a virtual
> method can execute one of any number of different methods and the
> method executed can vary from one call to the next

Ah, I now understand what you're getting at. I understand *that*
distinction, but hadn't realized that it was to that that you were
referring.

You are using "invocation" to mean the call to a virtual function
/interface/ (for want of a better word) before any overload resolution takes
place; and "execution" to mean the running of a particular overload of that
interface after resolution. I had understood both words to mean the latter
thing.

Incidentally: is this usage and meaning of "invoke" common in the C++
community? If so I for one have failed to pick up on it. We clearly need to
have unambiguous terms to distinguish the two stages in the process of
calling and dispatching a virtual method but I don't find invoke/execute
particularly felicitous. I see the standard itself talks about the "function
called" and its "final overrider" (5.2.2) and only uses the word "invoke"
when talking about macros.

> But simply because a particular application of a feature seems useless,
> is not sufficient grounds to ban that application.

I agree absolutely ... but I think that virtual function overrides being
allowed to differ in access types seems not merely useless, but also
confusing and potentially harmful. Nevertheless I'm not arguing that it
should be banned (too late in the day for that, even if there is a case for
it) -- just trying to understand the pros and cons better, and to understand
how/why it the language evolved the way it has.

-- 
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 7/28/2006 12:21:14 PM

In article news:<44c9dc11$1@news.kapsch.co.at>, Gerhard Menzl wrote:
> >> I don't care what the compiled code looks like, I am talking about
> >> source code cruft, ...
>
> This is getting a bit silly, I'm afraid, but I don't see lines mentioned
> anywhere in there.

Sorry. I know we're arguing over a small point, but I'm keen to discover
whether I'm missing something I ought to understand, or just failing to
make myself understood (I'm beginning to think it's a bit of both). Thanks
for your persistence ...

In an earlier post you wrote:
> Who said anything about lines? I said it's three times as much code.

and my I took that to mean that if you weren't talking about lines (i.e
*source* code) you must be talking about something else -- *binary* code.

I understand now that that's not what you meant. My fault.

> So you get two function declarations and one function invocation for one
> function declaration. Every parameter appears three times instead of
> once. That's a factor of 3 : 1. I don't care what the respective numbers
> of lines are, it's three times as much code that has to be maintained.

I see how you're counting that now. I don't see that as a big price to pay
for the the advantages I see in the longer form ... but I do now understand
why you say "three times as much".

> I concede that if you take derived classes into account, the overall
> ratio will be lower ...

Indeed.

> It is in the nature of idioms that they have to be thought about *less*,
> and that they are *less* likely to engender bugs, providing they are
> applied correctly, of course.

It's the nature of idioms that they are idiomatic. They are a useful aid to
communication among those who understand the idiom, while actually
hindering communication with those who don't. This is an area of C++ in
which I understand the communication but am surprised by the idiom.

> Any programmer vaguely familiar with object-oriented design and design
> patterns will recognize this instantly.

Not really ... I'm more than vaguely failiar with OO design and with
patterns, and experienced enough at C++ to recognize what the code is
doing, but I don't consider it a clear and intuitive use of the language.
I'd rather spell things out and minimize surprises than use language
'tricks'.

Then again, you haven't worked with some of the other programmers that I
have ...

> I don't see what "a single point of entry for debugging" buys you.
[snip]

It's defensive programming on my part. I always try to write code in a way
that will be easy to debug should the need arise. Fortunately the need
usually does not arise, but I still find it a useful exercise.

> If you need to log in the base class, then, of course, it ceases to be a
> mere abstract interface, and hiding the virtual function behind a public
> non-virtual function is justified, just as it is with precondition
> checks.

I do tend to write preconditions wherever I can, and I suspect I structure
the code in the same way even when there is no test I can reasonably make.

Call that my idiom, if you will.

> class NetworkObserver
>     {
>     public:
>        virtual void HandleNetworkEvent(NetworkEvent* event) = 0;
>     };
[snip]
> If you keep the original access level, HandleNetworkEvent() becomes
> part of the public interface of Communicator. Every client may call
> it. But of course that is not what you want.
[snip]

Thanks for the example. Yes, I see what you mean ... I don't remember
offhand exactly how I've done this in the past, I'll have to think about
it.

> I don't think the orthogonality of access level and overriding belongs
> in this category. Access level governs who is allowed to call a function
> or access a variable. It does not affect overriding. While it may
> surprise people, it's conceptually clean and consistent. That many C++
> programmers are not familiar enough with the language to be aware of
> this does not qualify it as a dirty quirk.

Logically (though not in C++) I feel that the access level of (in your
example above) HandleNetworkEvent is part of the definition of the
interface. If another class publishes that interface (derives from it
publicly) then I consider the publicness of HandleNetworkEvent to be a part
of that interface, and to have to be preserved. Some languages require
this, though C++ doesn't. When I think about the programming problem at an
abstract level (and maybe have to map that thought onto a real programming
language later) I find myself thinking about the interface as a whole, and
seems illogical to break that whole. This sort of conceptual consistency
seems more natural than what C++ provides.

You are right, though, that it is C++'s job to enable, not to prevent, so I
suppose there is no harm in it ... I just find it "feels wrong".
--
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 7/29/2006 3:04:11 PM

Daniel James wrote:
> In article news:<1154011341.612365.264030@m73g2000cwd.googlegroups.com>,
> Greg Herlihy wrote:
> > > Greg Herlihy wrote:
> > > > No, because there is a difference between invoking a method and
> > > > executing a method.
> > [I wrote]
> > > That's a pretty fine distinction -- and one that many
> > > users find confusing.  I'm not sure that it is helpful to
> > > make that distinction at all ...

> > The distinction between method invocation and method
> > execution is crucial for any understanding of what a virtual
> > method is. Because unlike a call to a non-virtual method -
> > which always executes the same method no matter how many
> > times it is called - a call to a virtual method can execute
> > one of any number of different methods and the method
> > executed can vary from one call to the next

> Ah, I now understand what you're getting at. I understand
> *that* distinction, but hadn't realized that it was to that
> that you were referring.

I'll admit that I still don't quite understand what he is
referring to.  We all know that virtual functions result in
dynamic binding, but what is the difference between invoking and
executing here?

> You are using "invocation" to mean the call to a virtual
> function /interface/ (for want of a better word) before any
> overload resolution takes place; and "execution" to mean the
> running of a particular overload of that interface after
> resolution. I had understood both words to mean the latter
> thing.

> Incidentally: is this usage and meaning of "invoke" common in
> the C++ community? If so I for one have failed to pick up on
> it. We clearly need to have unambiguous terms to distinguish
> the two stages in the process of calling and dispatching a
> virtual method but I don't find invoke/execute particularly
> felicitous.

The standard generally speaks of dynamic and static resolution,
I think.  Things like access control and overload resolution use
static resolution; function invocation itself, however, uses
dynamic resolution if the function found by static resolution is
declared virtual (or overrides a function which was declared
virtual).

> I see the standard itself talks about the "function called"
> and its "final overrider" (5.2.2) and only uses the word
> "invoke" when talking about macros.

I would say that "call" and "invoke" are pretty much synonyms
here.

--
James Kanze                                           GABI Software
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply kanze 7/31/2006 12:43:45 PM

Daniel James wrote:

>> Any programmer vaguely familiar with object-oriented design and
>> design patterns will recognize this instantly.
>
> Not really ... I'm more than vaguely failiar with OO design and with
> patterns, and experienced enough at C++ to recognize what the code is
> doing, but I don't consider it a clear and intuitive use of the
> language. I'd rather spell things out and minimize surprises than use
> language 'tricks'.

It seems that you misunderstood me again. I was not talking about the 
Private Interface pattern that would be instantly recognized (although 
it is old enough for that). What I meant is that everyone familiar with 
OO is also familiar with the separation of interface (abstract base 
class) and implementation (concrete derived class).

> I do tend to write preconditions wherever I can, and I suspect I
> structure the code in the same way even when there is no test I can
> reasonably make.

As soon as you check preconditions in the base class, your solution is 
justified, and the discussion is moot.

> Thanks for the example. Yes, I see what you mean ... I don't remember
> offhand exactly how I've done this in the past, I'll have to think
> about it.

To this day, I have not seen a satisfactory implementation in any of the 
stricter languages I have mentioned. I guess that people just don't care 
about exposing callback functions to clients that are not supposed to 
call them.


-- 
Gerhard Menzl

#dogma int main ()

Humans may reply by replacing the thermal post part of my e-mail address 
with "kapsch" and the top level domain part with "net".

{sig trimmed. -mod}


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Gerhard 8/1/2006 12:54:32 PM

In article news:<VA.00000e95.05f4c05d@nospam.aaisp.org>, Daniel James 
wrote:
> > If you keep the original access level, HandleNetworkEvent() becomes
> > part of the public interface of Communicator. Every client may call
> > it. But of course that is not what you want.
> [snip]
> 
> Thanks for the example. Yes, I see what you mean ... I don't remember
> offhand exactly how I've done this in the past, I'll have to think about
> it.

On checking I find that what I have generally done is to use the NVI idiom, 
as I described previously: In your example I would have given 
NetworkObserver a public non-virtual handle() method which would call a 
private (actually protected, in most of my code) virtual method that could 
be overridden by Communicator.

Note that this is straightforward in C++ where abstract classes can contain 
implementation, but not in Java or C hash.

-- 
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 8/1/2006 12:59:42 PM

In article news:<1154338746.434720.204080@75g2000cwc.googlegroups.com>, 
Kanze wrote:
> I'll admit that I still don't quite understand what he is
> referring to.  We all know that virtual functions result in
> dynamic binding, but what is the difference between invoking and
> executing here?

I *think* he's using "invoke" to describe the act of calling a (virtual) 
function. In his terminology -- which I find strange -- "invoke" does not 
include the process of virtual function lookup; it's purely the caller's 
perspective. He uses "execute" to describe the act of entering the "final 
overrider", after dynamic binding has happened.

I'm glad I'm not alone in being confused by this!

> > I see the standard itself talks about the "function called"
> > and its "final overrider" (5.2.2) and only uses the word
> > "invoke" when talking about macros.
> 
> I would say that "call" and "invoke" are pretty much synonyms
> here.

I think I would have found what Greg wrote easier to follow if he had used 
"call" rather than "invoke", though I agree that "call" and "invoke" are 
pretty much synonyms in most contexts.

"Invoke" can suggest some lengthy procedure or ritual (as in its meaning of 
"conjure"), though, whereas "call" may be as simple as shouting out. 

I don't know whether the writers of the standard had any particular purpose 
in mind in using "invoke" when talking about macros and "call" when talking 
about functions, but the use of different language does reinforce the 
difference between the two, and stress that a function call is different in 
nature from a macro expansion.

Maybe the standard needs to be written in its own metalanguage (like the 
Algol68 report)?
-- 
Daniel James             | djng
Sonadata Limited         | at sonadata
UK                       | dot co dot uk



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Daniel 8/1/2006 1:00:04 PM

35 Replies
71 Views

(page loaded in 0.409 seconds)


Reply: