multiple inheritance, why?

  • Follow


I heard that according to "The design and evolution of C++", multiple
inheritance was built into the language because of a dare.
Is that true?



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Serv 11/8/2003 1:55:43 PM

In article <boi5jj$4s2$1@news4.tilbu1.nb.home.nl>, Serv� Lau 
<i@bleat.nospam.com> writes
>I heard that according to "The design and evolution of C++", multiple
>inheritance was built into the language because of a dare.
>Is that true?

Do you  find that credible? When you see statements like this ask for a 
page reference and then check for yourself.



-- 
Francis Glassborow      ACCU
If you are not using up-to-date virus protection you should not be reading
this. Viruses do not just hurt the infected but the whole community.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Francis 11/9/2003 2:09:42 PM


"Serv� Lau" <i@bleat.nospam.com> wrote in message news:<boi5jj$4s2$1@news4.tilbu1.nb.home.nl>...
> I heard that according to "The design and evolution of C++", multiple
> inheritance was built into the language because of a dare.
> Is that true?

Actually the dare was to add polygamy to the langauge, but it was
banned in the United States so it was left out for reasons related to
unportability.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply trollking 11/9/2003 2:19:40 PM

Francis Glassborow escribi�:

> >I heard that according to "The design and evolution of C++", multiple
> >inheritance was built into the language because of a dare.
> >Is that true?
> 
> Do you  find that credible? When you see statements like this ask for a
> page reference and then check for yourself.

"... Brand Cox actually claimed that adding multipleinheritance to C++
was impossible [Cox, 1986]. Thus, multiple inheritance seemed moe of a
challenge. Since I had considered multiple inheritance as early as 1982
($2.13) and found a simple and efficient implementation technique in
1984, I couln't resist the challenge."

Bjarne Stroustrup. The design and evolution of C++, 12.1, pags 257-258.

Regards.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply iso 11/9/2003 10:50:21 PM

In article <3FAE974B.2807E2F6@terra.es>, Juli�n Albo 
<JULIANALBO@terra.es> writes
>Francis Glassborow escribi�:
>
>> >I heard that according to "The design and evolution of C++", multiple
>> >inheritance was built into the language because of a dare.
>> >Is that true?
>>
>> Do you  find that credible? When you see statements like this ask for a
>> page reference and then check for yourself.
>
>"... Brand Cox actually claimed that adding multipleinheritance to C++
>was impossible [Cox, 1986]. Thus, multiple inheritance seemed moe of a
>challenge. Since I had considered multiple inheritance as early as 1982
>($2.13) and found a simple and efficient implementation technique in
>1984, I couln't resist the challenge."
>
>Bjarne Stroustrup. The design and evolution of C++, 12.1, pags 257-258.

Hardly 'a dare' but you have also ignored the first two sentences of the 
same paragraph:

There were several reasons for choosing to work on multiple inheritance 
at the time: The design was further advanced, multiple inheritance 
fitted into the C++ type systems without major extensions, and the 
implementation could be done within Cfront. Another factor was purely 
irrational....

Now by seeing the source of the claim we can see that the claim 
exaggerates wildly. Also note that Brad Cox made his statement about C++ 
in his book on Objective C.

BTW The 'more of a challenge' related to the choice between implementing 
MI or templates first both were in Bjarne's long term objectives from 
fairly early on.

-- 
Francis Glassborow      ACCU
If you are not using up-to-date virus protection you should not be reading
this. Viruses do not just hurt the infected but the whole community.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Francis 11/10/2003 10:48:37 AM

Juli�n Albo wrote:
 > Francis Glassborow escribi�:
 >
 >>> I heard that according to "The design and evolution of C++",
 >>> multiple inheritance was built into the language because of a dare.
 >>> Is that true?
 >>
 >> Do you  find that credible? When you see statements like this ask
 >> for a page reference and then check for yourself.
 >
 > "... Brand Cox actually claimed that adding multipleinheritance to C++
 > was impossible [Cox, 1986]. Thus, multiple inheritance seemed moe of a
 > challenge. Since I had considered multiple inheritance as early as
 > 1982 ($2.13) and found a simple and efficient implementation
 > technique in 1984, I couln't resist the challenge."
 >
 > Bjarne Stroustrup. The design and evolution of C++, 12.1, pags
 > 257-258.

Well this doesn't necessarily mean that multiple inheritance wouldn't have
been there without this challenge aspect. It may have added some more
excitement, but i also read that BS was already interested in multiple
inheritance as early as 1982.

Maybe the challenge added motivation for being part of the language so soon,
but i would bet any of my organs i got in pair that it won't have been long
before it would have been included anyway...

Chris



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Christophe 11/10/2003 1:25:29 PM

"Christophe Lephay" <christophe-lephay@wanadoo.fr> wrote in message news:<bomipi$qtr$1@news-reader3.wanadoo.fr>...
> 
> Well this doesn't necessarily mean that multiple inheritance wouldn't have
> been there without this challenge aspect. It may have added some more
> excitement, but i also read that BS was already interested in multiple
> inheritance as early as 1982.

Correct. It's probably fair to say that I came to C++ with the
attitude that single inheritance was an oddly restricted notion.

> Maybe the challenge added motivation for being part of the language so soon,
> but i would bet any of my organs i got in pair that it won't have been long
> before it would have been included anyway...
> 

Yes. Here is a more complete quote from D&E (I strongly recommend D&E
as a source for information on why C++ is the way it is - there are so
many unecessary myths and conjectures around):
_____

In most people's minds multiple inheritance, the ability to have two
or more direct
base classes, was
THE
feature of 2.0.
I disagreed at the time because I felt that the sum of the
improvements to the type system
was of far greater practical importance.
Also, adding multiple inheritance
IN RELEASE 2.0
was a mistake.
Multiple inheritance belongs in C++, but is far less important than
parameterized types
-- and to some people, parameterized types are again less important
than exception
handling.
As it happened, parameterized types in the form of templates appeared
only in
Release 3.0, and exceptions even later.
I missed parameterized types much more than I would have missed
multiple inheritance.

There were several reasons for choosing to work on multiple
inheritance at the time:
The design was further advanced, multiple inheritance fits into the
C++ type
system without major extensions,
and the implementation could be done within Cfront.
Another factor was purely irrational.
Nobody seemed to doubt that I could implement templates efficiently.
Multiple inheritance, on the other hand, was widely supposed to be
very difficult to
implement efficiently. For example, in a summary of C++ in his book on
Objective C
Brad Cox actually claimed that adding multiple inheritance to C++ was
impossible.
Thus, multiple inheritance seemed more of a challenge.
Since I had considered multiple inheritance as early
as 1982 and found a simple and efficient
implementation technique in 1984, I couldn't
resist the challenge.
I suspect this to be the only case in which fashion affected the
sequence of events.
_____

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply bs 11/11/2003 10:07:55 AM

"Bjarne Stroustrup" <bs@research.att.com> wrote in message
news:188b3370.0311101057.238c2692@posting.google.com...
> "Christophe Lephay" <christophe-lephay@wanadoo.fr> wrote in message
news:<bomipi$qtr$1@news-reader3.wanadoo.fr>...
> >
> > Well this doesn't necessarily mean that multiple inheritance wouldn't
have
> > been there without this challenge aspect. It may have added some more
> > excitement, but i also read that BS was already interested in multiple
> > inheritance as early as 1982.
>
> Correct. It's probably fair to say that I came to C++ with the
> attitude that single inheritance was an oddly restricted notion.

ok, it seems I've heard only part of the story.
But since I now have the chance to talk to Mr. Stroustrup himself, just one
more question. Suppose MI could be redesigned in C++, would you take it out
and implement something like java's single inheritance, multiple interface
inheritance or are you happy with the way it is?



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Serv 11/11/2003 4:57:28 PM

"Serv� Lau" wrote:
> 
> But since I now have the chance to talk to Mr. Stroustrup himself, just one
> more question. Suppose MI could be redesigned in C++, would you take it out
> and implement something like java's single inheritance, multiple interface
> inheritance or are you happy with the way it is?
> 

Java programmers have to learn to work around that single inheritance,
multiple interface inheritance design. Often the result is code reuse
through cut-and-paste. It's simply not powerful enough.

-- 

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Pete 11/11/2003 10:48:42 PM

Serv� Lau wrote:
 > "Bjarne Stroustrup" <bs@research.att.com> wrote in message
 > news:188b3370.0311101057.238c2692@posting.google.com...
 >> It's probably fair to say that I came to C++ with the
 >> attitude that single inheritance was an oddly restricted notion.
 >
 > ok, it seems I've heard only part of the story.
 > But since I now have the chance to talk to Mr. Stroustrup himself,
 > just one more question. Suppose MI could be redesigned in C++, would
 > you take it out and implement something like java's single
 > inheritance, multiple interface inheritance or are you happy with the
 > way it is?

Well, it seems you want him to talk again about "an oddly restricted notion"
?

Chris



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Christophe 11/12/2003 9:13:32 AM

"Serv� Lau" <i@bleat.nospam.com> wrote in message news:<boqn77$qhl$1@news4.tilbu1.nb.home.nl>...

 > But since I now have the chance to talk to Mr. Stroustrup himself, just one
 > more question. Suppose MI could be redesigned in C++, would you take it out
 > and implement something like java's single inheritance, multiple interface
 > inheritance or are you happy with the way it is?

Neither. Given the impossible free hand, I'm sure I could improve the
design in detail, but there are more important and promising areas of
improvements (e.g. improve the support for generic programming, and in
particuler, more standard libraries) that are actually feasible, so
I'm unlikely to go there. If I did, however, I'd retain some general
form of multiple inheritance (that, is, I feel no urge to ban multiple
inheritance of implementatons - it can be useful - for example, see
examples in TC++PL).

   - Bjarne Stroustrup; http://www.research.att.com/~bs

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply bs 11/12/2003 9:21:47 AM

"Serv� Lau" <i@bleat.nospam.com> wrote in message
news:<boqn77$qhl$1@news4.tilbu1.nb.home.nl>...
> "Bjarne Stroustrup" <bs@research.att.com> wrote in message
> news:188b3370.0311101057.238c2692@posting.google.com...
> > "Christophe Lephay" <christophe-lephay@wanadoo.fr> wrote in message
> > news:<bomipi$qtr$1@news-reader3.wanadoo.fr>...

> > > Well this doesn't necessarily mean that multiple inheritance
> > > wouldn't have been there without this challenge aspect. It may
> > > have added some more excitement, but i also read that BS was
> > > already interested in multiple inheritance as early as 1982.

> > Correct. It's probably fair to say that I came to C++ with the
> > attitude that single inheritance was an oddly restricted notion.

> ok, it seems I've heard only part of the story.  But since I now have
> the chance to talk to Mr. Stroustrup himself, just one more
> question. Suppose MI could be redesigned in C++, would you take it out
> and implement something like java's single inheritance, multiple
> interface inheritance or are you happy with the way it is?

I can't speak for Stroustrup, but I find Java's solution rather
restrictive.  If there is a problem with multiple inheritance in C++, it
is that by default, inheritance in non-virtual.  If I have two classes,
L and R, both of which derive from B, I cannot create a D which derives
from both of them without obtaining two copies of B, unless the authors
of L and R thought to explicitly inherit virtually.

That said, I've encountered the problem exactly once in 15 years of C++,
so it can't be that prevelant or serious.

--
James Kanze           GABI Software        mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/     http://www.gabi-soft.fr
                    Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply kanze 11/12/2003 8:33:45 PM

Pete Becker <petebecker@acm.org> wrote in message news:<3FB124BA.7254E5B@acm.org>...
> "Serv� Lau" wrote:
> > 
> > But since I now have the chance to talk to Mr. Stroustrup himself, just one
> > more question. Suppose MI could be redesigned in C++, would you take it out
> > and implement something like java's single inheritance, multiple interface
> > inheritance or are you happy with the way it is?
> > 
> 
> Java programmers have to learn to work around that single inheritance,
> multiple interface inheritance design. Often the result is code reuse
> through cut-and-paste. It's simply not powerful enough.

One interesting - if somewhat moot - question is whether "multiple module 
mixin" as provided by Ruby would be powerful enough. In Ruby the limitation 
of single inheritance doesn't matter much because you can mixin any code you
need from modules. OTOH, Ruby is dynamically typed, so it doesn't need
interface inheritance and has less "final overrider issues".

In a statically typed language, one would need a "multiple interface 
inheritance, multiple mixin inheritance, single implementation inheritance"
model. In fact, I'm a bit surprised that this way wasn't taken by the C#
designers, since it seems to be a natural idea for a "Better Java".

Interestingly, this very model was proposed by the renowned "Taligent Desing
Guide", which prescribed that a class may inherit from multiple mixin classes,
but only one "domain model class" (I'm not sure whether "interface classes" 
were mentioned). 

Of course, in C++ the distinction between different categories of classes
is not directly expressible in the language. But changing that to be able
to define true Java-style interfaces directly doesn't lead very far: One
would need to distinguish between polymorphic classes, standalone concrete 
classes, trait classes, policy classes etc. pp.

Being a bit of a fan of Perl, I could imagine a general mechanism to allow
the programmer to define such categories: A "category" could define which
features belong to a class defined with it.

category interface { 
   ? typedef;            // may contain typedefs
   ? enum;               // may ... you get the idea
   . virtual ~;          // must have a virtual destructor
   ! template;           // mustn't have template members
   : public              // defaults members to be public
   ! protected, private; // mustn't have preotected or private members
   :^ virtual =0;        // can only contain pure virtual functions,
                         // which are default
};

interface IPrintable {
   void print();                     // pure virtual by default
   template<class M> outputTo(M& m); // error: template in interface class

.... etc. pp.

IMHO a tremendous opportunity to let good intentions go awry ...

Have fun,

Uwe

--

Remove the German nickname for @ from my email address before replying

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply schnitkerAffenschauk 11/12/2003 8:34:52 PM

kanze@gabi-soft.fr wrote:
> 
> If there is a problem with multiple inheritance in C++, it
> is that by default, inheritance in non-virtual.  If I have two classes,
> L and R, both of which derive from B, I cannot create a D which derives
> from both of them without obtaining two copies of B, unless the authors
> of L and R thought to explicitly inherit virtually.
> 

I understand what you're saying, but I don't think that's really the
problem. If the default were virtual inheritance,then the complaint
would be that I cannot create a D which derives from both L and R but
gets a separate copy of B from each of them. And the Java solution to
this problem, having two different keywords "class" and "interface,"
doesn't solve this, either: the base class designers still have to make
the "right" decision for the derived type.

-- 

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Pete 11/13/2003 9:22:32 PM

bs@research.att.com (Bjarne Stroustrup) wrote in message
news:<188b3370.0311111432.5f15388d@posting.google.com>...
> "Serv� Lau" <i@bleat.nospam.com> wrote in message
> news:<boqn77$qhl$1@news4.tilbu1.nb.home.nl>...

>  > But since I now have the chance to talk to Mr. Stroustrup himself,
>  > just one more question. Suppose MI could be redesigned in C++,
>  > would you take it out and implement something like java's single
>  > inheritance, multiple interface inheritance or are you happy with
>  > the way it is?

> Neither. Given the impossible free hand, I'm sure I could improve the
> design in detail, but there are more important and promising areas of
> improvements (e.g. improve the support for generic programming, and in
> particuler, more standard libraries) that are actually feasible, so
> I'm unlikely to go there. If I did, however, I'd retain some general
> form of multiple inheritance (that, is, I feel no urge to ban multiple
> inheritance of implementatons - it can be useful - for example, see
> examples in TC++PL).

I agree, but an even more important point might be that even with
regards to interface inheritance, I'm not sure we fully know what is
required.  I know that when I use Java, I end up using abstract classes
(instead of interfaces) for my interfaces, simply because the Java model
of an interface is insufficient for robust interfaces (read "with
programming by contract concepts").

--
James Kanze           GABI Software        mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/     http://www.gabi-soft.fr
                    Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply kanze 11/14/2003 10:29:22 AM

Pete Becker <petebecker@acm.org> wrote in message
news:<3FB2DC70.B77225A@acm.org>...
 > kanze@gabi-soft.fr wrote:

 > > If there is a problem with multiple inheritance in C++, it is that
 > > by default, inheritance in non-virtual.  If I have two classes, L
 > > and R, both of which derive from B, I cannot create a D which
 > > derives from both of them without obtaining two copies of B, unless
 > > the authors of L and R thought to explicitly inherit virtually.

 > I understand what you're saying, but I don't think that's really the
 > problem. If the default were virtual inheritance,then the complaint
 > would be that I cannot create a D which derives from both L and R but
 > gets a separate copy of B from each of them.

If that were the default, then we'd need a way to override it, exactly
as we have a way of overriding the current default.  I'm not complaining
about what you can do, just about the default: what is done when you
don't specify anything.

 > And the Java solution to this problem, having two different keywords
 > "class" and "interface," doesn't solve this, either: the base class
 > designers still have to make the "right" decision for the derived
 > type.

I was hardly suggesting the Java solution.  In fact, I didn't suggest a
solution, because while I don't consider the current situation perfect,
I also don't consider it a big enough problem to be worth the effort of
a language change.

--
James Kanze           GABI Software        mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/     http://www.gabi-soft.fr
                     Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply kanze 11/14/2003 1:08:54 PM

kanze@gabi-soft.fr wrote:
> 
> I was hardly suggesting the Java solution.

I would never accuse you of such a misguided thing. I was just exploring
the problem.

-- 

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Pete 11/14/2003 10:37:56 PM

"Pete Becker" <petebecker@acm.org> wrote in message
news:3FB2DC70.B77225A@acm.org...
> kanze@gabi-soft.fr wrote:
>
> I understand what you're saying, but I don't think that's really the
> problem. If the default were virtual inheritance,then the complaint
> would be that I cannot create a D which derives from both L and R but
> gets a separate copy of B from each of them.

Containment rather than inheritance would solve this
problem easily.  Make one (if not both) of 'L' and 'R'
contain a 'B'.  If not possible, make 'D' inherit one 'B'
from both 'L' and 'R', and add another contained 'B'
to 'D'.

Cheers!

 - Risto -



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Risto 11/15/2003 1:16:25 AM

Risto Lankinen wrote:
 >
 > "Pete Becker" <petebecker@acm.org> wrote in message
 > news:3FB2DC70.B77225A@acm.org...
 > > kanze@gabi-soft.fr wrote:
 > >
 > > I understand what you're saying, but I don't think that's really the
 > > problem. If the default were virtual inheritance,then the complaint
 > > would be that I cannot create a D which derives from both L and R but
 > > gets a separate copy of B from each of them.
 >
 > Containment rather than inheritance would solve this
 > problem easily.  Make one (if not both) of 'L' and 'R'
 > contain a 'B'.  If not possible, make 'D' inherit one 'B'
 > from both 'L' and 'R', and add another contained 'B'
 > to 'D'.
 >

No, containment doesn't work when inheritance is necessary, and that's
the context of this thread. Remember, too, that the assumption was that
someone else wrote L and R. You can't change 'em.

-- 

Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Pete 11/15/2003 10:18:16 AM

kanze@gabi-soft.fr wrote:
 > Pete Becker <petebecker@acm.org> wrote in message
 >> I understand what you're saying, but I don't think that's really
 >> the problem. If the default were virtual inheritance,then the
 >>  complaint would be that I cannot create a D which derives from
 >>  both L and R but gets a separate copy of B from each of them.
 >
 > If that were the default, then we'd need a way to override it, exactly
 > as we have a way of overriding the current default.  I'm not
 > complaining about what you can do, just about the default: what is
 > done when you don't specify anything.

But then the destructor should be virtual by default as well, as it needs to
be for your hierarchy to be polymorph, and it is the same arguement with
multiple inheritance (you don't have polymorphism without the virtual
inheritance)...

Chris



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Christophe 11/15/2003 10:19:38 AM

"Christophe Lephay" <christophe-lephay@wanadoo.fr> writes:

|>  kanze@gabi-soft.fr wrote:
|>   > Pete Becker <petebecker@acm.org> wrote in message
|>   >> I understand what you're saying, but I don't think that's really
|>   >> the problem. If the default were virtual inheritance,then the
|>   >> complaint would be that I cannot create a D which derives from
|>   >> both L and R but gets a separate copy of B from each of them.

|>   > If that were the default, then we'd need a way to override it,
|>   > exactly as we have a way of overriding the current default. I'm
|>   > not complaining about what you can do, just about the default:
|>   > what is done when you don't specify anything.

|>  But then the destructor should be virtual by default as well, as it
|>  needs to be for your hierarchy to be polymorph, and it is the same
|>  arguement with multiple inheritance (you don't have polymorphism
|>  without the virtual inheritance)...

There is some legitimate argument for having destructors virtual by
default.  It runs into two problems:

  - C compatibility -- don't forget that there are compiler generated
    no-op destructors even for POD's, and

  - the fact that there is no syntax for declaring non-virtuality.

The latter is an important point.  Functions should *not* be virtual in
general; that is an obvious mistake in Java (where I end up declaring
well over half my functions final).  And having a syntax for overriding
default virtual for the destructor, and another for overriding default
non virtual for the other functions, seems more complexity than the
problem is worth.  While viewed in isolation, making destructors virtual
by default may seem like a good idea, I think that the consistency of
having destructors obey the same rules as general functions (when
relevant) is even more important.

-- 
James Kanze                             mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/
                 Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France  +33 1 41 89 80 93

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply James 11/16/2003 4:16:40 PM

Pete Becker <petebecker@acm.org> writes:

|>  Risto Lankinen wrote:

|>   > "Pete Becker" <petebecker@acm.org> wrote in message
|>   > news:3FB2DC70.B77225A@acm.org...
|>   > > kanze@gabi-soft.fr wrote:

|>   > > I understand what you're saying, but I don't think that's
|>   > > really the problem. If the default were virtual
|>   > > inheritance,then the complaint would be that I cannot create a
|>   > > D which derives from both L and R but gets a separate copy of B
|>   > > from each of them.

|>   > Containment rather than inheritance would solve this problem
|>   > easily. Make one (if not both) of 'L' and 'R' contain a 'B'. If
|>   > not possible, make 'D' inherit one 'B' from both 'L' and 'R', and
|>   > add another contained 'B' to 'D'.

|>  No, containment doesn't work when inheritance is necessary, and
|>  that's the context of this thread. Remember, too, that the
|>  assumption was that someone else wrote L and R. You can't change
|>  'em.

Agreed.  In a certain sense, I think that we are putting too much into
my comment.  It was just a vague feeling, not a concrete proposal.  I
vaguely feel that inheritance should be virtual be default.  To go
beyond just a vague feeling, I would need some sort of concrete proposal
to evaluate: how do I change the default, at what level, etc.  Perhaps
my vague feeling would prove to be wrong.

In the meantime, I don't consider it enough of a problem to justify the
work necessary to create a concrete proposal.

-- 
James Kanze                             mailto:kanze@gabi-soft.fr
Conseils en informatique orient�e objet/
                 Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France  +33 1 41 89 80 93

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply James 11/16/2003 4:17:54 PM

"Pete Becker" <petebecker@acm.org> wrote in message
news:3FB58326.D2843796@acm.org...
 > Risto Lankinen wrote:
 >  >
 >  > "Pete Becker" <petebecker@acm.org> wrote in message
 >  > news:3FB2DC70.B77225A@acm.org...
 >  > > kanze@gabi-soft.fr wrote:
 >  > >
 >  > > I understand what you're saying, but I don't think that's really the
 >  > > problem. If the default were virtual inheritance,then the complaint
 >  > > would be that I cannot create a D which derives from both L and R but
 >  > > gets a separate copy of B from each of them.
 >  >
 >  > Containment rather than inheritance would solve this
 >  > problem easily.  Make one (if not both) of 'L' and 'R'
 >  > contain a 'B'.  If not possible, make 'D' inherit one 'B'
 >  > from both 'L' and 'R', and add another contained 'B'
 >  > to 'D'.
 >  >
 >
 > No, containment doesn't work when inheritance is necessary, and that's
 > the context of this thread. Remember, too, that the assumption was that
 > someone else wrote L and R. You can't change 'em.

Hence the "If not possible..."-part:

"If not possible, make 'D' inherit one 'B', from both 'L' and 'R',
and add another contained 'B' to 'D'."

This clearly is possible even if you didn't write 'L' nor 'R'.

Cheers!

  - Risto -



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Risto 11/17/2003 7:18:25 AM

Pete Becker wrote:
> "Serv� Lau" wrote:
> 
> Java programmers have to learn to work around that single inheritance,
> multiple interface inheritance design. Often the result is code reuse
> through cut-and-paste. It's simply not powerful enough.

Well as a C++ and Java framwork developer with over a decade of C++ 
experience, and 7 years of Java experience. I think I have 2 cents to 
offer on this point.

It has been my observation that the amount of code copy paste depends on 
the background of the Java programmer. The ones who came from a sound 
C++ background can often work around Java's lack of multiple inheritance 
without cut and paste. The technique that we use is to carefully analyze 
the use cases surrounding the affected inheritance hierarchy and then 
identify the main usage scenarios. Appropriate over-rides are then 
defined in Abstract classes that implement the appropriate interfaces in 
a way that the satisfies the various supported use cases. This leads to 
quite a few abstract classes, but the end result is that the 
recombination can be done with no copy pasting.

Of course this technique is only effective if you have a pretty good 
idea of how your framework is actually going to be used. This knowledge 
is only available for an application specific framework. So what usually 
happens is that framework users have to have their team gurus do this 
analysis, and develop the top level classes.

Regretably, the cited author's point is often quite correct. Currently, 
  this leads to cut and paste programming, since the last three years 
have seen more projects are being done by teams composed of 
inexperienced developers who do not have a strong technical architect on 
site. The current management trends are leading to more and more of this 
occurring. (Which is one reason I am considering going back to being 
more of a C++ developer than a Java developer).

But actually the technical aspect of C++ that I miss most in Java is not 
multiple inheritance but generic types with compile time type checking. 
circa jdk1.4 type safe containers can only be achieved via wrapper 
classes. The problem with achieving this through wrapper classes is that 
the two possible approaches involve combinatorial code explosion, or the 
possibility of run-time errors which can only be avoided by a 
combinatorial explosion of test driver scenarios. You can work around 
both of these issues, by writing a code generator to generate the 
wrapper code, or the test drivers, but most project managers will not 
let this happen, since the current management trend is to over come 
these issues by using cheaper inexperienced labor which will only make 
these problems worse.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply beerdrinker 11/17/2003 8:31:23 PM

"Risto Lankinen" <rlankine@hotmail.com> wrote in message news:<Te_tb.2701$g4.59824@news2.nokia.com>...
 > "Pete Becker" <petebecker@acm.org> wrote in message
 > news:3FB58326.D2843796@acm.org...
 >  > Risto Lankinen wrote:
 >  >  > Containment rather than inheritance would solve this
 >  >  > problem easily.  Make one (if not both) of 'L' and 'R'
 >  >  > contain a 'B'.  If not possible, make 'D' inherit one 'B'
 >  >  > from both 'L' and 'R', and add another contained 'B'
 >  >  > to 'D'.
 >  >  >
 >  >
 >  > No, containment doesn't work when inheritance is necessary, and that's
 >  > the context of this thread. Remember, too, that the assumption was that
 >  > someone else wrote L and R. You can't change 'em.
 >
 > Hence the "If not possible..."-part:
 >
 > "If not possible, make 'D' inherit one 'B', from both 'L' and 'R',
 > and add another contained 'B' to 'D'."
 >
 > This clearly is possible even if you didn't write 'L' nor 'R'.

It's not possible if D needs to override a member function of L and R.

Bob

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply belvis 11/18/2003 11:50:22 AM

Bob Bell wrote:
> It's not possible if D needs to override a member function of L and R.

You can always simulate it manually. The approach outlined below
doesn't permit cross-casting between the L and R parts of D, but
otherwise gets you there.

struct D
{
     struct LinD : L
     {
         D *parent;
         LinD(D *parent) : parent(parent) { }
         virtual void Lmethod() { /* override what you need */ }
     } my_l;
     struct RinD : R
     {
         D *parent;
         RinD(D *parent) : parent(parent) { }
         virtual void Rmethod() { /* override what you need */ }
     } my_r;
     D() : my_l(this), my_r(this) { }
     L *as_L() { return &my_l; }
     R *as_R() { return &my_r; }
};


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Hyman 11/18/2003 8:16:36 PM

"James Kanze" <kanze@alex.gabi-soft.fr> wrote in message
news:86fzgottvz.fsf@alex.gabi-soft.fr...

> The latter is an important point.  Functions should *not* be virtual in
> general; that is an obvious mistake in Java (where I end up declaring
> well over half my functions final).  And having a syntax for overriding
> default virtual for the destructor, and another for overriding default
> non virtual for the other functions, seems more complexity than the
> problem is worth.  While viewed in isolation, making destructors virtual
> by default may seem like a good idea, I think that the consistency of
> having destructors obey the same rules as general functions (when
> relevant) is even more important.

There could be an easy rule: dtor defaults to virtual IF the class has
virtual functions.

But imho it's more like a QoI issue, a compiler could detect and warn about
dangeous inheritance -- and if the programmer is not willing to pay
attention, it's unavoidable a problem anyway.

Paul



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Balog 11/21/2003 4:30:13 PM

<kanze@gabi-soft.fr> wrote in message
news:d6652001.0311140348.3b2c5e6a@posting.google.com...

> I was hardly suggesting the Java solution.  In fact, I didn't suggest a
> solution, because while I don't consider the current situation perfect,
> I also don't consider it a big enough problem to be worth the effort of
> a language change.

I could think a good improvement. As more and more I have a situation that I
have an abstract-like base class on one side (A), and grabbing
implementation from the other class (I).

To make it work I must carefully name functions, especially virtuals in I to
not match any in A, then use some glue template or something that puts them
together.

However suppose the language had a rule: if you get identical virtuals from
parents, the one of the class coming later in the parent list wins as a
final overrider.

Sure I understand how that is a way to create confusion, so if it would come
to a real modified C++, it shall happen only on programmer's order, like
using another keyword in the parent list before the class name.

Paul





      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Balog 11/21/2003 4:37:22 PM

In article <3fbdc310@andromeda.datanet.hu>, Balog Pal <pasa@lib.hu> 
writes
>There could be an easy rule: dtor defaults to virtual IF the class has
>virtual functions.

We have looked at that and it actually breaks existing code and is an 
invalid assumption because it assumes that it is always necessary to 
allow for destruction through a base class pointer or reference.



-- 
Francis Glassborow      ACCU
If you are not using up-to-date virus protection you should not be reading
this. Viruses do not just hurt the infected but the whole community.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Francis 11/22/2003 4:41:36 PM

 > Balog Pal <pasa@lib.hu> writes
 > >There could be an easy rule: dtor defaults to virtual IF the class has
 > >virtual functions.

Francis Glassborow <francis@robinton.demon.co.uk> wrote
 > We have looked at that and it actually breaks existing code and is an
 > invalid assumption because it assumes that it is always necessary to
 > allow for destruction through a base class pointer or reference.

How can it break existing code? Do you mean the obvious fix:

     class myBase {
     public:
         ~myBase() { cout << "Base\n"; } // NOT virtual
     };
     class myDer {
     public:
         ~myDer() { cout << "Derived and "; }
     }
     //...
     myBase *ptr = new myDer;
     //...
     delete ptr; // Does not display "Derived and"

This is what the proposal is designed to fix. Is there any code that
depends on this for correct behavior?

The only other way I can think of, is with mixed compilers -- i.e. one
module or library component is compiled with an old compiler, another
with the new one.

In general, can a program "tell" if a function (or the destructor) is
virtual?

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply allan_w 11/26/2003 9:16:02 AM

In article <7f2735a5.0311251707.65496b71@posting.google.com>, Allan W 
<allan_w@my-dejanews.com> writes
> > Balog Pal <pasa@lib.hu> writes
> > >There could be an easy rule: dtor defaults to virtual IF the class has
> > >virtual functions.
>
>Francis Glassborow <francis@robinton.demon.co.uk> wrote
> > We have looked at that and it actually breaks existing code and is an
> > invalid assumption because it assumes that it is always necessary to
> > allow for destruction through a base class pointer or reference.

 > How can it break existing code? Do you mean the obvious fix:


It breaks existing code because it breaks binary compatibility (changes 
the size and layout of vtables, which though not required by the 
standard are universally used) which matters because code such as COM 
processes interface to. This is not just a minor issue.

One reason that I have proposals for explicit declaration for compiler 
generated functions is that this would allow us a way round because we 
would then have the tools by which a programmer could explicitly state 
that she did not want a default virtual dtor. Without such a mechanism I 
would have to vote against a proposal to make a dtor virtual be default 
for classes with virtual members.


-- 
Francis Glassborow      ACCU
If you are not using up-to-date virus protection you should not be reading
this. Viruses do not just hurt the infected but the whole community.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Francis 11/26/2003 3:41:37 PM

Francis Glassborow <francis@robinton.demon.co.uk> wrote
 > Allan W <allan_w@my-dejanews.com> writes
 > > > Balog Pal <pasa@lib.hu> writes
 > > > >There could be an easy rule: dtor defaults to virtual IF the class has
 > > > >virtual functions.
 > >
 > >Francis Glassborow <francis@robinton.demon.co.uk> wrote
 > > > We have looked at that and it actually breaks existing code and is an
 > > > invalid assumption because it assumes that it is always necessary to
 > > > allow for destruction through a base class pointer or reference.
 >
 >  > How can it break existing code? Do you mean the obvious fix:
 >
 > It breaks existing code because it breaks binary compatibility (changes
 > the size and layout of vtables, which though not required by the
 > standard are universally used) which matters because code such as COM
 > processes interface to. This is not just a minor issue.

Okay, that's pretty much what I thought you meant.

There's already a problem mixing object code from compiler A, with object
code created from compiler B, even if they target the same platform.
This change would force a change to the alignment of the virtual tables,
so we would now have problems mixing object code from compiler A-old with
object code from compiler A-new.

(Unless it didn't export any classes with virtual functions.)

Even moving the dtor's virtual function to a special place in the vtable
doesn't help, because this makes a change to classes with EXPLICIT dtors.
Plus, code compiled with old compilers wouldn't know to call the virtual
dtor, so we'd get inconsistent results.

But even without a change to the standard, this issue is (at best) a
MAJOR annoyance. Each brand's virtual-table layout is now a de-facto
standard, in the sense that changing it would cause problems for it's
users. Suppose a compiler vendor was to figure out a way to improve
the compiled program's speed, trap errors more effectively, or in
general make their compiler better. If the way that they accomplish
this involves changing the vtable, they can NEVER implement this
change on existing platforms.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply allan_w 11/27/2003 10:24:04 AM

"Francis Glassborow" <francis@robinton.demon.co.uk> wrote:
> Allan W <allan_w@my-dejanews.com> wrote:
> 
>  > How can it break existing code? Do you mean the obvious fix:
> 
> It breaks existing code because it breaks binary compatibility (changes 
> the size and layout of vtables, which though not required by the 
> standard are universally used) which matters because code such as COM 
> processes interface to. This is not just a minor issue.

I can think of several ways of dealing with that.

1. Make dependance on non-portable binary interfaces explicit, through
   a conformant extension.  This is what Borland does for BCB C++
   classes that must be binary compatible with Delphi: They are
   declared as

     class  __declspec(delphiclass) MyClass

   allowing the compiler to apply special Delphi-rules to the class,
   without affecting regular C++ classes that are not so adorned.
   Something similar could be done with, say, __declspec(comclass)
   or__declspec(novirtualdestructor).

   I consider this The Right Way.  Implicit ties to external binary
   interfaces is a bad thing.

2. Store an extra destructor-pointer at a negative vtable-offset.  I
   don't know enough about COM to be sure that it will work, but if it
   does, it's a cheap and effective solution.

3. Store an extra destructor-pointer as a data member, or in a
   secondary vtable.

Implementors have plenty of viable options, whatever we choose to do.

- Anders



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Anders 11/29/2003 5:04:30 PM

"Anders J. Munch" <andersjm@dancontrol.dk> wrote
 > "Francis Glassborow" <francis@robinton.demon.co.uk> wrote:
 > > Allan W <allan_w@my-dejanews.com> wrote:
 > >
 > >  > How can it break existing code? Do you mean the obvious fix:
 > >
 > > It breaks existing code because it breaks binary compatibility (changes
 > > the size and layout of vtables, which though not required by the
 > > standard are universally used) which matters because code such as COM
 > > processes interface to. This is not just a minor issue.
 >
 > I can think of several ways of dealing with that.
 >
 > 1. ... a conformant extension ...
 >      class  __declspec(delphiclass) MyClass
 >    I consider this The Right Way.  Implicit ties to external binary
 >    interfaces is a bad thing.

Probably for the best.

 > 2. Store an extra destructor-pointer at a negative vtable-offset.  I
 >    don't know enough about COM to be sure that it will work, but if it
 >    does, it's a cheap and effective solution.

Ignore COM for a moment. This still won't work properly with legacy code
for two reasons.
    * If the destructor is specifically declared virtual, it's already
      in the vtable, and this proposal moves it out. Old code will call
      the wrong virtual functions.
    * If the destructor is not specifically declared virtual, this will
      add it, and new code will call it -- but if old code is responsible
      for creating the vtable, it won't be included.

 > 3. Store an extra destructor-pointer as a data member, or in a
 >    secondary vtable.

    Same problem -- it requires new code to do something that old code
    doesn't do. Furthermore, it will increase the size of all objects
    that have even one virtual function!

 > Implementors have plenty of viable options, whatever we choose to do.

But most of those options involve re-compiling all code, including
third-party libraries.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply allan_w 12/2/2003 10:32:40 AM

"Allan W" <allan_w@my-dejanews.com> wrote:
 > "Anders J. Munch" <andersjm@dancontrol.dk> wrote
 >
 >  > 2. Store an extra destructor-pointer at a negative vtable-offset.  I
 >  >    don't know enough about COM to be sure that it will work, but if it
 >  >    does, it's a cheap and effective solution.
 >
 > Ignore COM for a moment. This still won't work properly with legacy code
 > for two reasons.
 >     * If the destructor is specifically declared virtual, it's already
 >       in the vtable, and this proposal moves it out. Old code will call
 >       the wrong virtual functions.

No, old code will call the same old virtual functions at the same old
locations, including the destructor.  There's no /moving/ going on,
it's an extra /copy/.

 >     * If the destructor is not specifically declared virtual, this will
 >       add it, and new code will call it -- but if old code is responsible
 >       for creating the vtable, it won't be included.

Nice try, you almost had me there ;)

Creating an object with code compiled with compiler A, and delete'ing
it in code compiled with compiler B is a messy proposition.  I would
use factory functions for both the creating and the deleting if I had
any kind of choice.

But ok, let's suppose there is no choice.  We have a shiny new
compiler but need to use an old binary-only library, and the old
library has a factory function that returns objects for us to destroy
with delete.  We have a problem.

A problem that can be solved.  The vtable is a linkage-object.
Whenever deleting a pointer to an affected class, emit a new vtable
for the class.  Then have the linker discard the vtable in the library
file because an object by the same name exists in user code, which is
what linkers typically do.  The old code now creates an object with
the correct - new - vtable.

 >  > Implementors have plenty of viable options, whatever we choose to do.
 >
 > But most of those options involve re-compiling all code, including
 > third-party libraries.

Or patch the header with a #pragma to request compatibility with older
versions.

Or use the
    --nothing-interesting-has-happened-since-1998
compatibility switch on affected projects.

- Anders



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Anders 12/3/2003 11:13:47 AM

"Anders J. Munch" <andersjm@dancontrol.dk> wrote
 > "Allan W" <allan_w@my-dejanews.com> wrote:
 >  > "Anders J. Munch" <andersjm@dancontrol.dk> wrote
 >  >
 >  >  > 2. Store an extra destructor-pointer at a negative vtable-offset.  I
 >  >  >    don't know enough about COM to be sure that it will work, but if it
 >  >  >    does, it's a cheap and effective solution.
 >  >
 >  > Ignore COM for a moment. This still won't work properly with legacy code
 >  > for two reasons.
 >  >     * If the destructor is specifically declared virtual, it's already
 >  >       in the vtable, and this proposal moves it out. Old code will call
 >  >       the wrong virtual functions.
 >
 > No, old code will call the same old virtual functions at the same old
 > locations, including the destructor.  There's no /moving/ going on,
 > it's an extra /copy/.

If I understand you correctly:
    * In all cases, the address of the virtual destructor is stored
      at a negative offset in the vtable. Call this Address 1.
    * If the destructor would have been virtual under the OLD rules
      (i.e. declared virtual, or has a base with a virtual dtor)
      then it is ALSO stored in the vtable at the same place it would
      previously have been stored. Call this Address 0.

New code is smart enough to call the destructor via Address 1.
Old code will call the destructor through Address 0 if it exists, or
else not at all.

Now, this question:

 >  >     * If the destructor is not specifically declared virtual, this will
 >  >       add it, and new code will call it -- but if old code is responsible
 >  >       for creating the vtable, it won't be included.

can be reworded:
     If new code tries to call the destructor via Address 1,
     but old code has created the vtable (and so the address is only
     at Address 0, or perhaps not at all), don't we crash?

 > Nice try, you almost had me there ;)
 >
 > Creating an object with code compiled with compiler A, and delete'ing
 > it in code compiled with compiler B is a messy proposition.  I would
 > use factory functions for both the creating and the deleting if I had
 > any kind of choice.

I was thinking specifically about the case where compiler B is a newer
version of the same brand as compiler A -- a special case that no
reasonable compiler maker is going to ignore.

 > But ok, let's suppose there is no choice.  We have a shiny new
 > compiler but need to use an old binary-only library, and the old
 > library has a factory function that returns objects for us to destroy
 > with delete.  We have a problem.
 >
 > A problem that can be solved.  The vtable is a linkage-object.
 > Whenever deleting a pointer to an affected class, emit a new vtable
 > for the class.  Then have the linker discard the vtable in the library
 > file because an object by the same name exists in user code, which is
 > what linkers typically do.  The old code now creates an object with
 > the correct - new - vtable.

But the new code doesn't try to delete through a pointer to the
affected class. It tries to delete through a pointer to some base
class.

I think there are some important details missing.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply allan_w 12/5/2003 12:48:26 PM

"Allan W" <allan_w@my-dejanews.com> wrote:
> 
> If I understand you correctly:
>     * In all cases, the address of the virtual destructor is stored
>       at a negative offset in the vtable. Call this Address 1.
>     * If the destructor would have been virtual under the OLD rules
>       (i.e. declared virtual, or has a base with a virtual dtor)
>       then it is ALSO stored in the vtable at the same place it would
>       previously have been stored. Call this Address 0.

This is not quite what I meant, so I'll elaborate.  If the destructor
would have been virtual under the old rules, there is no change. The
destructor is located and looked up in the same place as always.

If the destructor would have been non-virtual under the old rules, but
is virtual under the new rules, a pointer to the virtual dtor is
placed at a negative vtable offset.  The dtor is only looked up at a
negative vtable offset as a last resort; for any subclass with an
explicitly declared virtual dtor, that dtor is accesible from the
usual, backwards-compatible vtable position, which is then preferred.

> 
> Now, this question:
[...]
> can be reworded:
>      If new code tries to call the destructor via Address 1,
>      but old code has created the vtable (and so the address is only
>      at Address 0, or perhaps not at all), don't we crash?

No.  The old code contains *a* vtable; the new code contains another
vtable for the same class, by the same name.  The old vtable is
eliminated at link time, causing the old code to refer to the new
vtable.

> 
> But the new code doesn't try to delete through a pointer to the
> affected class. It tries to delete through a pointer to some base
> class.

That's exactly the situation we are trying to fix.  Deleting an object
through a pointer to a base clas with no virtual destructor is
undefined behaviour, so under the current rules your new code would
have a bug.  At least with the proposed change, a complete recompile
would have the effect of silently fixing that bug.

- Anders



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Anders 12/5/2003 11:43:53 PM

 > "Allan W" <allan_w@my-dejanews.com> wrote:
 > >      If new code tries to call the destructor via [the negative offset],
 > >      but old code has created the vtable (and so the address is only
 > >      at [a positive offset], or perhaps not at all), don't we crash?

"Anders J. Munch" <andersjm@dancontrol.dk> wrote
 > No.  The old code contains *a* vtable; the new code contains another
 > vtable for the same class, by the same name.  The old vtable is
 > eliminated at link time, causing the old code to refer to the new
 > vtable.

I suspect that's a lot harder than you think. But I don't have any
experience writing linkers, so I'm just guessing... we'll assume that
this is reasonably possible.

 > > But the new code doesn't try to delete through a pointer to the
 > > affected class. It tries to delete through a pointer to some base
 > > class.
 >
 > That's exactly the situation we are trying to fix.  Deleting an object
 > through a pointer to a base clas with no virtual destructor is
 > undefined behaviour, so under the current rules your new code would
 > have a bug.  At least with the proposed change, a complete recompile
 > would have the effect of silently fixing that bug.

If it tries to delete through a base pointer, it is nevertheless calling
through the vtable of the derived class. But the new compiler might very
well have never seen a definition of the derived class, so it has no way
to re-create the vtable.

This example is contrived only in one way -- presumably a person who
understands how to generate a class factory, also understands the neeed
for virtual destructors.

     // Header file - - - - - - - - - - - - - - - - - - - - - - - - - - -
     class Base {
     public:
        // ... other functions, including some virtual ...
        // This will become virtual under new rules, but
        ~Base(); // not virtual with old rules
     };
     Base *BaseFactory(int);
     // Note no mention of Der1 or Der2

     // Library code, compiled ONLY with old compiler - - - - - - - - - -
     #include "header.h"
     class Der1 : public Base {
     public:
         // Implements for all Base members
         ~Der1();
     };
     Class Der2 : public Base {
     public:
         // Implements for all Base members including dtor
         ~Der2();
     };
     Base *BaseFactory(int i) {
         switch (i) {
             case 1 : return new Der1;
             case 2 : return new Der2;
             default: throw "Invalid BaseFactory() value";
     }   }

     // New code, compiled with NEW compiler - - - - - - - - - - - - - -
     #include "header.h"
     int main() {
         Base *b = BaseFactory(2);
         delete b; // How does this call Der2::~Der2?
     }

Since the new compiler never sees the definition of Der1 or Der2, how
is it supposed to create new vtables for it?

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply allan_w 12/9/2003 10:52:40 AM

"Allan W" <allan_w@my-dejanews.com> wrote:
> "Anders J. Munch" <andersjm@dancontrol.dk> wrote
>      // New code, compiled with NEW compiler - - - - - - - - - - - - - -
>      #include "header.h"
>      int main() {
>          Base *b = BaseFactory(2);
>          delete b; // How does this call Der2::~Der2?
>      }

How this calls Der2::~Der2?  It doesn't.  Undefined behaviour ensues.

However, the old compiler fares no better.  If you compile your
example entirely with the old compiler, you get UB also, because Base
doesn't have a virtual destructor.  So nothing's lost - unless you
have reason to prefer one kind of UB over another.

- Anders



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Anders 12/9/2003 8:02:45 PM

Pete Becker wrote:
> "Serv� Lau" wrote:
> 
>>But since I now have the chance to talk to Mr. Stroustrup himself, just one
>>more question. Suppose MI could be redesigned in C++, would you take it out
>>and implement something like java's single inheritance, multiple interface
>>inheritance or are you happy with the way it is?
>>
> 
> 
> Java programmers have to learn to work around that single inheritance,
> multiple interface inheritance design. Often the result is code reuse
> through cut-and-paste. It's simply not powerful enough.
> 

I have always found the lack of multiple inheritance in Java a real 
pain!  Indeed with multiple interface and object delegation you can 
simulate only a limited form of multiple inheritance (we have a paper 
about multiple inheritance in Java: "On Multiple Inheritance in Java", 
L.Bettini, M.Loreti, B.Venneri, Technology of Object-Oriented Languages, 
Systems and Architectures, Proc. of TOOLS Eastern Europe 2002, 
http://music.dsi.unifi.it/abstracts/multipinh-abs.html 
http://music.dsi.unifi.it/papers/multipinh.ps.gz).

I struggle with this lack many times especially when you have threads: 
if you inherit from thread you have already spent your chance of 
inheriting...  Runnable interface does not solve the problem since then 
you'll have to build a thread around your object and when you refer the 
thread you do not actually refer your real object...

Lorenzo

-- 
+-----------------------------------------------------+
|  Lorenzo Bettini          ICQ# lbetto, 16080134     |
|  PhD in Computer Science                            |
|  Dip. Sistemi e Informatica, Univ. di Firenze       |
|  Tel +39 055 4796741, Fax +39 055 4796730           |
|  Florence - Italy        (GNU/Linux User # 158233)  |
|  Home Page        : http://www.lorenzobettini.it    |
|  http://music.dsi.unifi.it         XKlaim language  |
|  http://www.lorenzobettini.it/purple    Cover Band  |
|  http://www.gnu.org/software/src-highlite           |
|  http://www.gnu.org/software/gengetopt              |
|  http://www.lorenzobettini.it/software/gengen       |
+-----------------------------------------------------+


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Lorenzo 12/19/2003 6:44:58 PM

39 Replies
72 Views

(page loaded in 0.48 seconds)

Similiar Articles:











7/5/2012 2:35:38 PM


Reply: