Topic: Protected Inheritance


Author: "Andrei Alexandrescu" <alexandrescua@micromodeling.com>
Date: 1999/02/17
Raw View
Valentin Bonnard wrote in message <36C046BE.4233@clipper.ens.fr>...
>No, sadly it won't, because of some strange [moderators, I can say
>stupid ?]
>rule in the standard, which prohibits making template parameters
>friends.

Guess what. I removed the "class" keyword in my friend declaration and MSVC
6 gladly accepted the code.

template <class T>
class DontDeriveFromMyTemplateParameter
{
    friend T;
    DontDeriveFromMyTemplateParameter() {}
};

class Something : virtual public
DontDeriveFromMyTemplateParameter<Something>
{
public:
    Something() {}
};

class SomethingElse : public Something
{
};

Something s1;          // fine
SomethingElse s2;      // compile-time error

So, who's right?
Also, to Scott: I tried the copy constructor loophole and I couldn't
instantiate MoreDerived as you predicted. Again: who's right?

Andrei



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]





Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1999/02/17
Raw View
On 17 Feb 99 05:59:17 GMT, Andrei Alexandrescu

>Guess what. I removed the "class" keyword in my friend declaration and MSVC
>6 gladly accepted the code.

I've tried this on como too, and it is not accepted.
   friend class T; // error
   friend T; // error
Como is probably right, because the standard forbids making a class
a friend to a template parameter.  However, I tend to think that
there's no harm in allowing this kind of friendship.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: smeyers@aristeia.com (Scott Meyers)
Date: 1999/02/17
Raw View
In article <36C046BE.4233@clipper.ens.fr>, bonnard@clipper.ens.fr says...
> Scott Meyers wrote:
>
> > True, but don't forget the copy constructor:
> >
> >   class MoreDerived: public Something {
> >   public:
> >     MoreDerived()
> >     : Something(*new Something) {}   // initialize DontDeriveFromSomething
> >   };                                 // via copy ctor
>
> Could you explain why you think that it should work ?

It should work because the virtual base class has an implicit public copy
constructor, so a more derived class could initialize
DontDeriveFromSomething via this constructor.  Alas, that's not what the
code snippet above does.  This is the correct code:

  class MoreDerived: public Something {
  public:
    MoreDerived()
    : DontDeriveFromSomething(*new Something) {}
  };

To prevent this, DontDerivedFromSomething needs to declare its copy
constructor private.

> > >By the way, I tried to templatize the idiom, and I thought it should work.
> >
> > I think it should, too.
>
> No, sadly it won't, because of some strange [moderators, I can say stupid
> ?]  rule in the standard, which prohibits making template parameters
> friends.

Can somebody summarize for me the motivation behind this rule?  If, as I
suspect, this has already been hashed to death in this newsgroup, feel free
to just point me to a subject thread I can look up at Deja News.

Thanks,

Scott

--
Scott Meyers, Ph.D.                  smeyers@aristeia.com
Software Development Consultant      http://www.aristeia.com/
Visit http://meyerscd.awl.com/ to demo the Effective C++ CD


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]





Author: "Andrei Alexandrescu" <alexandrescua@micromodeling.com>
Date: 1999/02/18
Raw View
Siemel Naran wrote in message ...
>Como is probably right, because the standard forbids making a class
>a friend to a template parameter.  However, I tend to think that
>there's no harm in allowing this kind of friendship.

But it's the other way 'round: I make the template parameter friend to the
template. Is this also forbidden?
Also, sorry for my error, I was speaking about MSVC 5, not 6.

Andrei



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]





Author: Valentin Bonnard <bonnard@clipper.ens.fr>
Date: 1999/02/16
Raw View
Scott Meyers wrote:

> True, but don't forget the copy constructor:
>
>   class MoreDerived: public Something {
>   public:
>     MoreDerived()
>     : Something(*new Something) {}   // initialize DontDeriveFromSomething
>   };                                 // via copy ctor

Could you explain why you think that it should work ?

> >By the way, I tried to templatize the idiom, and I thought it should work.
>
> I think it should, too.

No, sadly it won't, because of some strange [moderators, I can say
stupid ?]
rule in the standard, which prohibits making template parameters
friends.

--

Valentin Bonnard

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]






Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/02/05
Raw View
Scott Meyers wrote in message ...
>  class Base {
>  public:
>    Base();
>  };
>
>  class Derived: private virtual Base {};
>
>  class MoreDerived: public Derived {};
>
>  MoreDerived m;

>The FDIS (and presumably the
>standard -- I really should buy a copy, shouldn't I?) addresses the
>matter
>in 12.6.2.  Paragraph 2 seems to back you up (I've omitted stuff that
>doesn't seem germane here):


Paragraph two talks about names, but not accessibility.  Paragraph six (in
the standard, I haven't checked FDIS) says for this case:

"[Base is] initialized by the constructor of [MoreDerived.] ... If [Base]
does not have an accessible default constructor, the initialization is ill
formed."

So I think this means that virtual base classes should never be private in a
class intended for derivation.  Note that MoreDerived could be changed to be
legal:
  class MoreDerived: public Derived, private virtual Base {};
but the developer has to look at Derived's private stuff to figure this out.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Scott Meyers" <smeyers@aristeia.com>
Date: 1999/02/05
Raw View
Siemel Naran <sbnaran@localhost.localdomain.COM> wrote in message news:slrn7bjmm5.q36.sbnaran@localhost.localdomain...
>On 04 Feb 99 17:00:40 GMT, Scott Meyers <smeyers@aristeia.com> wrote:
>
>>  2 Names in a mem-initializer-id are looked up in the scope of the
>>    constructor's class and, if not found in that scope, are looked
>>    up in the scope containing the constructor's definition.
>
>>Does 12.6.2 really mean that private virtual base classes may be
>>initialized only by their immediate descendant classes (excluding
>>friendship issues)?
>
>I think that MSVC is indeed right in compiling your code:
>  class Base { public: explicit Base(int); };
>  class Sub1 : virtual private Base { public: Sub1(); };
>  class Sub2 : virtual private Base { public: Sub2(); };
>  class Derived : public Sub1, public Sub2 { public:
>     Derived() : Base(1), Sub1(), Sub2() { }
>  };
>  int main() { Derived(); }
>The compilers como and egcs also compile this.
>
>This is because the Derived class really owns the Base subobject.

Where do you find support for this notion of "owernership" in the standard?

>The above class Derived is entirely equivalent to this
>  class Derived : virtual private Base, public Sub1, public Sub2 { public:
>     Derived() : Base(1), Sub1(), Sub2() { }
>  };

Maybe.  Compilers that lay out objects in the manner described in the ARM
would put an extra ptr-to-vbase in this latter definition of Derived, I believe.
At any rate, I'd still like to see support in the standard for your
interpretation.

FWIW, I *hope* it's true that indirect derived classes
can initialize private virtual bases, but I still think 12.6.2 can be
read to the contrary.

Scott

Scott Meyers, Ph.D.                  Voice: 503/638-6028
Author:  Effective C++ CD            Fax:   503/638-6614
         Effective C++               Email: smeyers@aristeia.com
         More Effective C++          WWW:   http://www.aristeia.com/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Scott Meyers" <smeyers@aristeia.com>
Date: 1999/02/05
Raw View
Andrei Alexandrescu <alexandrescua@micromodeling.com> wrote in message news:36b9fd49.0@10.1.1.65...
>The "final class" C++ idiom is:
>
>class DontDeriveFromSomething
>{
>    friend class Something;
>    DontDeriveFromSomething() {}
>};
>
>class Something : virtual public DontDeriveFromSomething
>{
>public:
>    Something() {}
>};
>
>class SomethingElse : public Something
>{
>};
>
>SomethingElse s;    // compile-time error

True, but don't forget the copy constructor:

  class MoreDerived: public Something {
  public:
    MoreDerived()
    : Something(*new Something) {}   // initialize DontDeriveFromSomething
  };                                 // via copy ctor

>By the way, I tried to templatize the idiom, and I thought it should work.

I think it should, too.

>P.S. Nice to see you on clcm again.

Thanks.  Let's see how long it takes me to make a fool of myself :-)

Scott

Scott Meyers, Ph.D.                  Voice: 503/638-6028
Author:  Effective C++ CD            Fax:   503/638-6614
         Effective C++               Email: smeyers@aristeia.com
         More Effective C++          WWW:   http://www.aristeia.com/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnard@clipper.ens.fr>
Date: 1999/02/06
Raw View
Scott Meyers wrote:

> This might be a reasonable example, but I'm not convinced C++ works the
> way
> you describe.  In particular, I don't think further derivation is
> supposed
> to be prohibited by the use of private virtual inheritance.  I fed this
> to
> VC6:
>
>   class Base {
>   public:
>     Base();
>   };
>
>   class Derived: private virtual Base {};
>
>   class MoreDerived: public Derived {};
>
>   MoreDerived m;
>
> It took it without complaint.  Since we all know VC6 is a perfect
> compiler, this should settle the matter.

Well, actually no, MSVC is wrong here. Base is private to Derived
and thus inaccessible in MoreDerived.

However, this is trivial to work-arround:

class MoreDerived: public Derived, virtual Base {};

is valid.

--

Valentin Bonnard
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Larry Brasfield" <clcppm-poster@this.is.invalid>
Date: 1999/02/07
Raw View
I am answering Scott's question and addressing an issue
raised by Francis.  (It's post conservation in action.)

Francis Glassborow wrote in message <7sAoNOBfshu2EwFV@robinton.demon.co.uk>...
>In article <HEbu2.18017$202.8772558@news1.teleport.com>, Scott Meyers
><smeyers@aristeia.com> writes
>>Does 12.6.2 really mean that private virtual base classes may be
>>initialized only by their immediate descendant classes (excluding
>>friendship issues)?

Paragraph 6 of 12.6.2 says "All sub-objects representing
virtual base classes are initialized by the constructor of the
most derived class" and "A mem-initializer naming a virtual
base class shall be ignored during execution of the constructor
of any class that is not the most derived class."  (This relates
to the earlier stated requirement that the most derived class
constructor initilizes virtual bases before anything else.)  What
this means is that it doesn't matter whether intermediate base
classes do the initialization or not; the most derived constructor
is supposed to take over that responsibility.

>I always understood that making a virtual base private was a waste of
>time because:
>
>class A {};
>
>class B: private virtual A {};
>
>class C: public virtual A, public B {};
>
>now provides access to the private virtual base.  Maybe my memory is at
>fault.

I think calling that inheritance structure "a waste of
time" is to lose sight of what is being controlled by
making derivation private.  It is not so much to guard
the base against outside corruption as to restrict the
interface exposed by the derived class.  The above
private (virtual) inheritance does that for class B.  The
fact that class C (or its designer, more accurately) has
chosen to expose its A base is C's (designer's) affair,
of no concern to the design of B.  Presumably, what
utility A had for B survives sharing (which is implicit
in virtual inheritance) by classes that derive from B.
That utility is independent of whether those classes
elect to expose A as part of their interface.

--Larry Brasfield
Above opinions may be mine alone.
(Humans may reply at unundered larry_br@sea_net.com )





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/07
Raw View
In article <hZ7v2.2348$GN.1054@news.rdc1.wa.home.com>, Larry Brasfield
<clcppm-poster@this.is.invalid> writes
>I think calling that inheritance structure "a waste of
>time" is to lose sight of what is being controlled by
>making derivation private.  It is not so much to guard
>the base against outside corruption as to restrict the
>interface exposed by the derived class.  The above
>private (virtual) inheritance does that for class B.  The
>fact that class C (or its designer, more accurately) has
>chosen to expose its A base is C's (designer's) affair,
>of no concern to the design of B.  Presumably, what
>utility A had for B survives sharing (which is implicit
>in virtual inheritance) by classes that derive from B.
>That utility is independent of whether those classes
>elect to expose A as part of their interface.

My feeling is that the concept is better provided by using virtual
protected inheritance.  I guess that is a style issue, but it does I
think, warn less experienced designers that the inheritance they are
using provides less protection than they might expect.


Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Scott Meyers" <smeyers@aristeia.com>
Date: 1999/02/04
Raw View
[I've included comp.std.c++ for reasons that should be obvious...]

Bill Wade <bill.wade@stoner.com> wrote in message
news:79aesq$qlr$1@uuneo.neosoft.com...

>Consider a reference counting base class, RefCnt.  In an MI hierarchy,
>reference counted objects will probably use public virtual inheritance
>from RefCnt.
>
>For development purposes I may want to monitor the RefCnt behavior of
some
>classes (perhaps I suspect I'm leaving "dead" circles of references
>somewhere).  I can make a mixin class DbgRefCnt, which also virtually
>inherits from RefCnt, to tell me what is going on.
>
>DbgRefCnt is probably not part of the public interface of the classes
that
>use it.  It is a temporary implementation detail.  As such, classes
would
>normally use private inheritance.  However I really only want at most
one
>DbgRefCnt object per RefCnt object.  This means that I should use
virtual
>inheritance for DbgRefCnt.  If I use virtual private inheritance I lose
>the ability for further derivation (constructor of DbgRefCnt is not
>accessible to further derived classes).  For this case it would seem
>appropriate to use protected inheritance.

This might be a reasonable example, but I'm not convinced C++ works the
way
you describe.  In particular, I don't think further derivation is
supposed
to be prohibited by the use of private virtual inheritance.  I fed this
to
VC6:

  class Base {
  public:
    Base();
  };

  class Derived: private virtual Base {};

  class MoreDerived: public Derived {};

  MoreDerived m;

It took it without complaint.  Since we all know VC6 is a perfect
compiler,
this should settle the matter.  Ahem.  The FDIS (and presumably the
standard -- I really should buy a copy, shouldn't I?) addresses the
matter
in 12.6.2.  Paragraph 2 seems to back you up (I've omitted stuff that
doesn't seem germane here):

  1 In the definition of a  constructor  for  a  class,  initializers
for
    direct  and  virtual base subobjects and nonstatic data members can
be
    specified by a ctor-initializer, which has the form
       ctor-initializer:
               : mem-initializer-list
       mem-initializer-list:
               mem-initializer
               mem-initializer , mem-initializer-list
       mem-initializer:
               mem-initializer-id ( expression-listopt )
       mem-initializer-id:
               ::opt nested-name-specifieropt class-name
               identifier

  2 Names in a mem-initializer-id are looked up in the scope of  the
con-
    structor's class and, if not found in that scope, are looked up in
the
    scope containing the constructor's definition.

However, let us not forget that constructors don't have names (12.1,
para
1).  So I'm not quite sure how to interpret the above.

Does 12.6.2 really mean that private virtual base classes may be
initialized only by their immediate descendant classes (excluding
friendship issues)?

Scott

Scott Meyers, Ph.D.                  Voice: 503/638-6028
Author:  Effective C++ CD            Fax:   503/638-6614
         Effective C++               Email: smeyers@aristeia.com
         More Effective C++          WWW:   http://www.aristeia.com/





      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]





Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/02/05
Raw View
On 04 Feb 99 17:00:40 GMT, Scott Meyers <smeyers@aristeia.com> wrote:

>  2 Names in a mem-initializer-id are looked up in the scope of the
>    constructor's class and, if not found in that scope, are looked
>    up in the scope containing the constructor's definition.

>Does 12.6.2 really mean that private virtual base classes may be
>initialized only by their immediate descendant classes (excluding
>friendship issues)?

I think that MSVC is indeed right in compiling your code:
  class Base { public: explicit Base(int); };
  class Sub1 : virtual private Base { public: Sub1(); };
  class Sub2 : virtual private Base { public: Sub2(); };
  class Derived : public Sub1, public Sub2 { public:
     Derived() : Base(1), Sub1(), Sub2() { }
  };
  int main() { Derived(); }
The compilers como and egcs also compile this.

This is because the Derived class really owns the Base subobject.
The above class Derived is entirely equivalent to this
  class Derived : virtual private Base, public Sub1, public Sub2 { public:
     Derived() : Base(1), Sub1(), Sub2() { }
  };

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]





Author: "Andrei Alexandrescu" <alexandrescua@micromodeling.com>
Date: 1999/02/05
Raw View
Scott Meyers wrote in message ...
[snip]
>I fed this to VC6:
>
>  class Base {
>  public:
>    Base();
>  };
>
>  class Derived: private virtual Base {};
>
>  class MoreDerived: public Derived {};
>
>  MoreDerived m;
>
>It took it without complaint.  Since we all know VC6 is a perfect
>compiler,
>this should settle the matter.  Ahem.
[snip]

I don't want to look like evangelizing VC6, but here it's not its problem.
The "final class" C++ idiom is:

class DontDeriveFromSomething
{
    friend class Something;
    DontDeriveFromSomething() {}
};

class Something : virtual public DontDeriveFromSomething
{
public:
    Something() {}
};

class SomethingElse : public Something
{
};

SomethingElse s;    // compile-time error

Please note that the name of the very base class is important, because it
will appear in the error message, which otherwise is not very informative.

By the way, I tried to templatize the idiom, and I thought it should work.
But VC5 chokes ignores the case when the template parameter is made a friend
of the template class. Who's wrong? Here's the code:

template <class T>
class DontDeriveFromMyTemplateParameter
{
    friend class T;
    DontDeriveFromMyTemplateParameter() {}
};

class Something : virtual public
DontDeriveFromMyTemplateParameter<Something>
{
public:
    Something() {}    // compile-time error here???
};

class SomethingElse : public Something
{
};

SomethingElse s;

As of the protected inheritance issue, I also look forward to seeing a sound
conceptual definition of it.

Andrei

P.S. Nice to see you on clcm again.



      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/02/05
Raw View
In article <HEbu2.18017$202.8772558@news1.teleport.com>, Scott Meyers
<smeyers@aristeia.com> writes
>Does 12.6.2 really mean that private virtual base classes may be
>initialized only by their immediate descendant classes (excluding
>friendship issues)?

I always understood that making a virtual base private was a waste of
time because:

class A {};

class B: private virtual A {};

class C: public virtual A, public B {};

now provides access to the private virtual base.  Maybe my memory is at
fault.



Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]