Topic: virtual base class construction
Author: John Max Skaller <maxtal@suphys.physics.su.oz.au>
Date: 1995/09/05 Raw View
kanze@gabi-soft.fr (J. Kanze) wrote:
>John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
>|> In article <40g1nl$2jo@gabi.gabi-soft.fr>, J. Kanze <kanze@gabi-soft.fr> wrote:
>|> >John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
>|> >|> For example how do you do assignments in the presence of
>|> >|> virtual bases? What stops the data of the virtual base being assigned
>|> >|> more than once?
>|> > C&
>|> > C::operator( C const& other )
>|> > {
>|> > if ( this != &other )
>|> > {
>|> > this->~C() ;
>|> > new ( this ) C( other ) ;
>|> > }
>|> > return *this ;
>|> > }
>|> >
>|> >No duplicate assignment of the virtual bases of C.
>
>|> I don't understand, this does NOT work.
>
>Yes it does.
Sorry! you're right! It works.
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1995/09/05 Raw View
Scott Meyers (smeyers@netcom.com) wrote:
|> Distribution:
|> In article <MATT.95Aug29110526@physics10.Berkeley.EDU> kanze@gabi-soft.fr (J. Kanze) writes:
|> | Distribution:
|> | John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
|> | |> In article <40g1nl$2jo@gabi.gabi-soft.fr>, J. Kanze <kanze@gabi-soft.fr> wrote:
|> | |> >John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
|> | |> >
|> | |> >|> For example how do you do assignments in the presence of
|> | |> >|> virtual bases? What stops the data of the virtual base being assigned
|> | |> >|> more than once?
|> | |> >
|> | |> > C&
|> | |> > C::operator( C const& other )
|> | |> > {
|> | |> > if ( this != &other )
|> | |> > {
|> | |> > this->~C() ;
|> | |> > new ( this ) C( other ) ;
|> | |> > }
|> | |> > return *this ;
|> | |> > }
|> | |> >
|> | |> >No duplicate assignment of the virtual bases of C.
|> |
|> | |> I don't understand, this does NOT work.
|> |
|> | Yes it does. At least, it does according to the standard, and on all
|> | compilers I've been able to try it with. (It doesn't compile under
|> | certain versions of cfront, due to a compiler error.)
|> | The whole questions hinges on defining what the right thing is. I would
|> | contend that in many (most?) cases, the right thing is to destruct the
|> | existing target object, and copy the right hand side into it. This is
|> | *exactly* what my code does.
|> |
|> | Since it uses the destructor for destruction, and the copy constructor
|> | for copying, *and* the compiler is required to do these correctly, it
|> | ``works''.
|> |
|> | Note that typically, it will in fact do extra work, since the generated
|> | code will fiddle around with the vptr's.
|> The trick works, but at the risk of changing the dynamic type of the target
|> of the assignment. For example:
|> class A {};
|> class B: virtual public A{};
|> class C: virtual public A{};
|> class D: public B, public C {};
|> B *pb1 = new D;
|> B *pb2 = new D;
|> *pb1 = *pb2; // calls B::operator= and changes the dynamic
|> // type of *pb1 to B, because its vtbl gets
|> // changed
|> Note that this is not a problem with MI, it's a problem with the
|> implementation strategy that James proposed. The same problem arises under
|> SI.
I knew there was a reason that you didn't like it. (I also knew that
the reason pretty much convinced my at the time you first presented it.
I cannot say that I really like the trick, only that in the presence of
virtual base classes, I like the alternatives less.)
|> In fairness, assignment in the presence of inheritance is always tricky.
|> For example, my code above performs a partial assignment (due to the
|> call to B::operator=) unless operator= is declared virtual. And if it's
|> declared virtual, you have to figure out what to do with mixed type
|> assignments like this:
|> A *pa1 = new C;
|> A *pa2 = new B;
|> *pa1 = *pa2; // assign a B to a C via C::operator=
You also end up with a plethora of operator='s in the derived classes,
since ``operator=( D const* )'' does *not* override ``operator=( B
const* )''.
In cases where polymorphism is important, I tend to work with reference
semantics, and assign smart pointers (or even ordinary pointers). I
also furnish a `clone' function, so in the cases where deep copy is
appropriate, the user has that option.
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle--
--Beratung in industrieller Datenverarbeitung
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1995/08/29 Raw View
Distribution:
John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
|> In article <40g1nl$2jo@gabi.gabi-soft.fr>, J. Kanze <kanze@gabi-soft.fr> wrote:
|> >John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
|> >
|> >|> For example how do you do assignments in the presence of
|> >|> virtual bases? What stops the data of the virtual base being assigned
|> >|> more than once?
|> >
|> > C&
|> > C::operator( C const& other )
|> > {
|> > if ( this != &other )
|> > {
|> > this->~C() ;
|> > new ( this ) C( other ) ;
|> > }
|> > return *this ;
|> > }
|> >
|> >No duplicate assignment of the virtual bases of C.
|> I don't understand, this does NOT work.
Yes it does. At least, it does according to the standard, and on all
compilers I've been able to try it with. (It doesn't compile under
certain versions of cfront, due to a compiler error.)
|> This stops
|> an object being assigned to itself. That isn't the problem.
|> The problem is:
|> B
|> / L R
|> /
|> D
|> If the assignment of D calls the assignments of L and R
|> before assigning the non-inherited members of D, and
|> the assignments of L and R each call the assignment of B
|> before assigning their non-inherited members, then the
|> assignment of B is called TWICE.
No disagreement, except that the assignment operator of D (or C, in my
example) never calls the assignment operator of its base classes.
|> In the case of assigments entirely generated by the compiler,
|> it is possible for the compiler to do the right thing.
|> AFAIK the committee has NOT required this: double assignment
|> is permitted. (I hate this but I can live with it)
|> In the case where USER written assignments are involved
|> AS WELL as compiler generated assignments, there is NO way
|> to ensure the compiler does the right thing.
Why doesn't my example work.
The whole questions hinges on defining what the right thing is. I would
contend that in many (most?) cases, the right thing is to destruct the
existing target object, and copy the right hand side into it. This is
*exactly* what my code does.
Since it uses the destructor for destruction, and the copy constructor
for copying, *and* the compiler is required to do these correctly, it
``works''.
Note that typically, it will in fact do extra work, since the generated
code will fiddle around with the vptr's.
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle--
--Beratung in industrieller Datenverarbeitung
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: smeyers@netcom.com (Scott Meyers)
Date: 1995/08/30 Raw View
Distribution:
In article <MATT.95Aug29110526@physics10.Berkeley.EDU> kanze@gabi-soft.fr (J. Kanze) writes:
| Distribution:
| John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
| |> In article <40g1nl$2jo@gabi.gabi-soft.fr>, J. Kanze <kanze@gabi-soft.fr> wrote:
| |> >John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
| |> >
| |> >|> For example how do you do assignments in the presence of
| |> >|> virtual bases? What stops the data of the virtual base being assigned
| |> >|> more than once?
| |> >
| |> > C&
| |> > C::operator( C const& other )
| |> > {
| |> > if ( this != &other )
| |> > {
| |> > this->~C() ;
| |> > new ( this ) C( other ) ;
| |> > }
| |> > return *this ;
| |> > }
| |> >
| |> >No duplicate assignment of the virtual bases of C.
|
| |> I don't understand, this does NOT work.
|
| Yes it does. At least, it does according to the standard, and on all
| compilers I've been able to try it with. (It doesn't compile under
| certain versions of cfront, due to a compiler error.)
| The whole questions hinges on defining what the right thing is. I would
| contend that in many (most?) cases, the right thing is to destruct the
| existing target object, and copy the right hand side into it. This is
| *exactly* what my code does.
|
| Since it uses the destructor for destruction, and the copy constructor
| for copying, *and* the compiler is required to do these correctly, it
| ``works''.
|
| Note that typically, it will in fact do extra work, since the generated
| code will fiddle around with the vptr's.
The trick works, but at the risk of changing the dynamic type of the target
of the assignment. For example:
class A {};
class B: virtual public A{};
class C: virtual public A{};
class D: public B, public C {};
B *pb1 = new D;
B *pb2 = new D;
*pb1 = *pb2; // calls B::operator= and changes the dynamic
// type of *pb1 to B, because its vtbl gets
// changed
Note that this is not a problem with MI, it's a problem with the
implementation strategy that James proposed. The same problem arises under
SI.
In fairness, assignment in the presence of inheritance is always tricky.
For example, my code above performs a partial assignment (due to the
call to B::operator=) unless operator= is declared virtual. And if it's
declared virtual, you have to figure out what to do with mixed type
assignments like this:
A *pa1 = new C;
A *pa2 = new B;
*pa1 = *pa2; // assign a B to a C via C::operator=
Scott
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/08/15 Raw View
In article <40g1nl$2jo@gabi.gabi-soft.fr>, J. Kanze <kanze@gabi-soft.fr> wrote:
>John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
>
>|> For example how do you do assignments in the presence of
>|> virtual bases? What stops the data of the virtual base being assigned
>|> more than once?
>
> C&
> C::operator( C const& other )
> {
> if ( this != &other )
> {
> this->~C() ;
> new ( this ) C( other ) ;
> }
> return *this ;
> }
>
>No duplicate assignment of the virtual bases of C.
I don't understand, this does NOT work. This stops
an object being assigned to itself. That isn't the problem.
The problem is:
B
/ L R
/
D
If the assignment of D calls the assignments of L and R
before assigning the non-inherited members of D, and
the assignments of L and R each call the assignment of B
before assigning their non-inherited members, then the
assignment of B is called TWICE.
In the case of assigments entirely generated by the compiler,
it is possible for the compiler to do the right thing.
AFAIK the committee has NOT required this: double assignment
is permitted. (I hate this but I can live with it)
In the case where USER written assignments are involved
AS WELL as compiler generated assignments, there is NO way
to ensure the compiler does the right thing.
If you define all the assignments yourself you can arrange to
prevent duplicate assignments of members.
The problem ONLY arises for virtual bases, and it is not
important if they contain no data. Note assigments do NOT
copy virtual table pointers, so assignments of classes without
data can be optimised away. This is why I can probably live
with the current rule.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: Bryan Drew <bdrew@hi-q.demon.co.uk>
Date: 1995/08/10 Raw View
In reply to article: <407ol9$m03@metro.ucc.su.OZ.AU>
from maxtal@Physics.usyd.edu.au (John Max Skaller):
Are you saying that ALL OO designs should treat the equivalent of virtual
base classes as abstract, or just those designs that are going to be
realised in C++ ??
IMHO there is no reason why a pure OO design should restrict the equivalent
of virtual base classes to be abstract. If the design is then to be
implemented in a language (e.g. C++) whose support for such class hierarchy
designs is limited, then further design is required to work round these
restrictions imposed by the language.
I am not saying that the language is faulty in this instance, just very
restrictive.
The existance of such language restrictions and hence the need for
additional design is painful but not insurmountable, although it will
increase development costs! As such language designers ideally should
review such restrictions to see if the reasons why they were originally
introduced are still valid, with a view to removing such restrictions
whenever possible.
So when you say "Just do it the right way", I assume you mean use an
appropriate work around when implementing in C++. To say that such a
mechanism "is mandatory for a quality OO library class" is too generalistic
and incorrect. C++ is not the only OO language available, and some other
languages may support multiple inheritance in a more coherent manner.
This is clearly an area where the General C++ Design Rule "Don't try to
force people" [D&E of C++ Section 4.2] was compromised to achieve
other requirements.
--
Bryan Drew, Email: bdrew@hi-q.demon.co.uk
Hi-Q Systems Limited, Tel : +44 (0)1252-815035
Hi-Q House, Ancells Court, Fax : +44 (0)1252-815022
Fleet, Hants GU13 8UZ UK
Author: Bryan Drew <bdrew@hi-q.demon.co.uk>
Date: 1995/08/07 Raw View
In article: <401gnk$mk0@metro.ucc.su.OZ.AU> maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
> If you examine several other problems, however you will
> probably come to that conclusion as a rule of thumb as I have.
>
> For example how do you do assignments in the presence of
> virtual bases? What stops the data of the virtual base being assigned
> more than once?
>
> More theoretically -- virtual bases have a property of
> uniqueness which allows them to represent the type of their class.
> This is exactly what you need to construct a SET of types whose
> intersection is that which a derived class can be said to _BE_ a subtype.
> This kind of relationship strongly suggests it ought to be
> an relationship between semantic interfaces -- NOT representations.
>
> Categorically, this is a PRODUCT of interfaces.
> (And a SUM of data)
>
> On the other hand non-virtual bases containing data are
> NOT unique (and it's a bug in the language you can't name them,
> not even by a path-name). Inheritance here is little more than
> composition with forwarding functions.
>
> Categorically, this is a SUM of interfaces.
> (And a product of data)
>
> Categorically, sums and products are DUAL notions.
> Interfaces and representations are also dual.
>
> Another example: a struct is a PRODUCT. (Cartesian!).
> A discriminated union is a SUM.
>
> The structure of these things is the same if you reverse
> all your concepts (that's what 'dual' means).
>
> What does all this mean? Obviously, interesecting
> interfaces is what virtual bases are good at -- but
> if two virtual bases both have a common virtual base,
> what does it mean if there are representations?
>
> It cannot work! You have to waste the data and provide
> a unifying representation!
>
> FOR EXAMPLE:
>
> struct Complex { float x,y; .. }
> struct Real : virtual Complex { ?????? }
>
> Why waste the 'y' value which is always 0 in a Real number?
> Now consider the interface instead of the representation:
>
> struct Complex {
> virtual float x()const=0;
> virtual float y()const=0; .. }
> struct Real : virtual Complex {
> float y()const { return 0.0; } ...
>
> This works, it supports polymorphism and subtyping correctly.
> Supplying data does NOT.
>
> The best way to do this is to use mixins, which Barton and
> Nackman speak of as separating the interface from the implementation.
>
> Doing this allows "isA" to be a relationship expressed
> by virtual inheritance between abstract
> classes to build up concepts independently of representation.
> Representation independence is the key to polymorphism and
> transparent optimisation of tested software without
> risking its correctness in more than a highly localised place.
>
I am not sure I completely agree with you. I could argue that the
following hierarchy is a reasonably sensible approach.
class Person
{
char* name;
....
};
class Employee
: public virtual Person
{
int employee_number;
....
};
class Golfer
: public virtual Person
{
int handicap;
....
};
class Company_Golf_Club_Member
: public Employee, public Golfer
{
int rank;
....
};
Here we have the situation where a Golfer IS A Person. An Employee
IS A Person. And a Company_Golf_Club_Member IS both A Golfer, and
AN Employee !!
N.B. An Employee need not be a Golfer and visa-versa.
This to me would seem to be a natural mechanism to represent the
class hierarchy identified above. However the C++ virtual base class
mechanism causes the above implementation to take on a number of
warts, especially in the use of non-default constructors.
Taking this case in point, a Person must always have a name, date of
birth etc., and so to provide a default constructor for such a class
is meaningless! These warts generally lead one away from developing
hierarchies that utilise virtual inheritance and hence cause one to
pervert the class hierarchy instead!!
While the above example is possibly not the best illustration, (I am
sure many readers of this newsgroup could come up with a hierarchy
that does not involve virtual inheritance), it does however show my
point.
My original posting at the start of this thread requested the reasons
*why* non-default virtual base class constructors required calling
from the most derived class, rather than the lowest class where all
the virtual class instances had been inherited. So far *no*
responses to this thread have addressed this question. I am sure
there are good technical reasons for this, and I could possibly make
a reasonable guess. However, I would like to know the reason(s) from
the horse's mouth so to speak.
For example if we were to add the following to the above hierarchy:
class Club_Captain
: public Company_Golf_Club_Member
{
int years_as_captain;
....
}
Why does the class Club_Captain need to call Person's constructor
directly, rather than letting the constructor of
Company_Colf_Club_Member sort it out? This would seem to be a much
better approach (from the software authors point of view).
Bryan.
--
Bryan Drew, Email: bdrew@hi-q.demon.co.uk
Hi-Q Systems Limited, Tel : +44 (0)1252-815035
Hi-Q House, Ancells Court, Fax : +44 (0)1252-815022
Fleet, Hants GU13 8UZ UK
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/08/08 Raw View
In article <606002587wnr@hi-q.demon.co.uk>,
Bryan Drew <bdrew@hi-q.demon.co.uk> wrote:
>In article: <401gnk$mk0@metro.ucc.su.OZ.AU> maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
[virtual bases should be abstract]
>> If you examine several other problems, however you will
>> probably come to that conclusion as a rule of thumb as I have.
>
>I am not sure I completely agree with you.
Probably because I didn't explain well enough.
>I could argue that the
>following hierarchy is a reasonably sensible approach.
If you did, you would be arguing that there is a fault
in C++. I'm arguing there ISNT and that you have simply failed
to understand the consequences of the language as it is
currently -- and correctly -- defined. [took me 3 years
to figure this one out]
> class Person
> {
> char* name;
> };
>
> class Employee
> : public virtual Person
> {
> int employee_number;
> };
>
> class Golfer
> : public virtual Person
> {
> int handicap;
> };
>
> class Company_Golf_Club_Member
> : public Employee, public Golfer
> {
> int rank;
> };
>
>Here we have the situation where a Golfer IS A Person. An Employee
>IS A Person. And a Company_Golf_Club_Member IS both A Golfer, and
>AN Employee !!
No problem. Just get rid of the data!
>N.B. An Employee need not be a Golfer and visa-versa.
>
>This to me would seem to be a natural mechanism to represent the
>class hierarchy identified above.
It would seem so naively, but further examination
proves otherwise: the whole point of your original post
is that this DOESN'T work very well.
You argued, as many have before (including me!)
that this is fault in the c++ language.
It isn't. The language is correct as it stands.
There's no other sensible alternative.
>However the C++ virtual base class
>mechanism causes the above implementation to take on a number of
>warts, especially in the use of non-default constructors.
Yes, so the naive implementation is just that -- naive.
>
>Taking this case in point, a Person must always have a name, date of
>birth etc., and so to provide a default constructor for such a class
>is meaningless! These warts generally lead one away from developing
>hierarchies that utilise virtual inheritance and hence cause one to
>pervert the class hierarchy instead!!
NO. Just do it the right way!
Here it is: (WILL Someone put this in the FAQ please!!)
struct Person
{
virtual char* name()const =0;
protected: void operator=(Person const&);
};
struct Employee
: public virtual Person
{
virtual int employee_number() const = 0;
protected: void operator=(const Employee&);
};
struct Person_impl : public virtual Person {
char *thename;
Person_impl(char *n) : thename(n) {}
char *name()const { return thename; }
};
struct Employee_impl : public virtual Employee, public Person_impl {
int thenumber;
Employee_impl(char *nam, int num)
: Person_impl(name), thenumber(num) {}
int employee_number ()const { return thenumber; }
};
Perhaps you can see how separating the interface and implementation
solves the problems with initialisation -- and at the same time
permits extra representations to be provided.
This works for multiple inheritance fine.
Yes, it is extra long winded and not necessary for
"quick one off application programming". But it is mandatory
for a quality OO library class. (IMHO)
>My original posting at the start of this thread requested the reasons
>*why* non-default virtual base class constructors required calling
>from the most derived class, rather than the lowest class where all
>the virtual class instances had been inherited.
It isn't possible to define such a class coherently and stably.
ANY class further down can just "grab" the class as a virual base.
This leads back exactly to the original problem -- multiple
initialisations.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/08/06 Raw View
In article <3up5ne$4gv@fsgm01.fnal.gov>,
David Sachs <sachs@fnal.fnal.gov> wrote:
>maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>
>>In article <3u6mnq$bag@fsgm01.fnal.gov>,
>>David Sachs <sachs@fnal.fnal.gov> wrote:
>>>
>>>I am annoyed that the standards committee waffled badly on handling
>>>the default version of operator=. The proposed standard specifically
>>>states, that the number of times a virtual base is copied can be
>>>implmentation dependent.
>
>> I agree. It's pretty bad. However, a virtual base
>>shouldn't have any user data in it anyhow.
>
>I do feel that a virtual base should normally be initialized via its
>default constructor. This does NOT mean that it should have no data
>whatsoever.
If you examine several other problems, however you will
probably come to that conclusion as a rule of thumb as I have.
For example how do you do assignments in the presence of
virtual bases? What stops the data of the virtual base being assigned
more than once?
More theoretically -- virtual bases have a property of
uniqueness which allows them to represent the type of their class.
This is exactly what you need to construct a SET of types whose
intersection is that which a derived class can be said to _BE_ a subtype.
This kind of relationship strongly suggests it ought to be
an relationship between semantic interfaces -- NOT representations.
Categorically, this is a PRODUCT of interfaces.
(And a SUM of data)
On the other hand non-virtual bases containing data are
NOT unique (and it's a bug in the language you can't name them,
not even by a path-name). Inheritance here is little more than
composition with forwarding functions.
Categorically, this is a SUM of interfaces.
(And a product of data)
Categorically, sums and products are DUAL notions.
Interfaces and representations are also dual.
Another example: a struct is a PRODUCT. (Cartesian!).
A discriminated union is a SUM.
The structure of these things is the same if you reverse
all your concepts (that's what 'dual' means).
What does all this mean? Obviously, interesecting
interfaces is what virtual bases are good at -- but
if two virtual bases both have a common virtual base,
what does it mean if there are representations?
It cannot work! You have to waste the data and provide
a unifying representation!
FOR EXAMPLE:
struct Complex { float x,y; .. }
struct Real : virtual Complex { ?????? }
Why waste the 'y' value which is always 0 in a Real number?
Now consider the interface instead of the representation:
struct Complex {
virtual float x()const=0;
virtual float y()const=0; .. }
struct Real : virtual Complex {
float y()const { return 0.0; } ...
This works, it supports polymorphism and subtyping correctly.
Supplying data does NOT.
The best way to do this is to use mixins, which Barton and
Nackman speak of as separating the interface from the implementation.
Doing this allows "isA" to be a relationship expressed
by virtual inheritance between abstract
classes to build up concepts independently of representation.
Representation independence is the key to polymorphism and
transparent optimisation of tested software without
risking its correctness in more than a highly localised place.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: kanze@lts.sel.alcatel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 1995/07/25 Raw View
In article <DC75Kr.E69@online.tmx.com.au> tony@online.tmx.com.au (Tony
Cook) writes:
|> John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
|> : In article <3u6mnq$bag@fsgm01.fnal.gov>,
|> : David Sachs <sachs@fnal.fnal.gov> wrote:
|> : >
|> : >I am annoyed that the standards committee waffled badly on handling
|> : >the default version of operator=. The proposed standard specifically
|> : >states, that the number of times a virtual base is copied can be
|> : >implmentation dependent.
|> : I agree. It's pretty bad. However, a virtual base
|> : shouldn't have any user data in it anyhow.
|> Doesn't basic_ios (or ios) contain user data?
Yes, but in the standard, it is not a virtual base (at least not in
the standard).
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/07/25 Raw View
In article <RAINES.95Jul14103000@esaw01.SLAC.Stanford.EDU>,
Paul E. Raines <raines@esaw01.SLAC.Stanford.EDU> wrote:
>In article <648258751wnr@hi-q.demon.co.uk> Bryan Drew <bdrew@hi-q.demon.co.uk> writes:
>>> Can someone please explain to me why, when inheriting a
>>> base class virtually, all most derived classes must call
>>> the constructor of the virtual base class, even those that
>>> only contain a single instance of the base class.
>>>
>>> I would be grateful for the views of others in this matter.
>>> Do other people find this requirement as annoying as I do?
>>>
>
>Yes! Absolutely yes! Very annoying. It makes the virtual base classes useless
>in C++, IMHO.
No. It makes virtual bases with data requiring non-default
initialisation a Bad Idea (tm).
Personally, I think you should stick to completely abstract
(no data) for virtual bases unless you really know what you are doing.
Read "Scientific and Enginerring C++" (Barton and Nackman)
to understand how to use abstract virtual bases and concrete
derived classes to separate interfacce from implementation.
(The ideas are fundamental to the mixin style)
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: liv@tribeca.ios.com (Wendy Liu)
Date: 1995/07/22 Raw View
Shashaanka (shashank@sashimi.wwa.com) wrote:
: Please Read ARM. You will get your answer.
: Bryan Drew <bdrew@hi-q.demon.co.uk> wrote:
: >Can someone please explain to me why, when inheriting a
: >base class virtually, all most derived classes must call
: >the constructor of the virtual base class, even those that
: >only contain a single instance of the base class.
: >Taking the inheritance lattice:
: > C X
: > \ / \
: > \ / \
: > \ / \
: > \ / \
: > A B
: > \ /
: > \ /
: > \ /
: > \ /
: > V
: >I can understand that class X needs to call V's constructor
: >directly because the compiler is unable to determine
: >whether to use the constructor behaviour defined by A or B
: >in order to initialise V.
: >However, the language also requires class C to call V's
: >constructor, even though using A's constructor behaviour to
: >initialise V in this case is both logical and unambiguous.
: >The problem is further exacerbated if further derivations
: >are made from C, each new specialisation having to
: >redeclare the redundant construction of V.
: >Is there any real reason for this, or is it there just to
: >make the life of compiler writers easier ?
: >A code example follows:
: >class V
: >{
: > private:
: > const int i;
: > public:
: > V( const int in_i) : z(in_z) {}
: >};
: >class A : public virtual V
: >{
: > A() : V(3) {}
: >};
: >class B : public virtual V
: >{
: > B() : V(5) {}
: >};
: >class C : public A
: >{
: > C() {} // Why must this be illegal ?
: > // Surely the constuction of V
: > // is unambiguous due to single
: > // inheritance through A.
: >};
: >class X : public A, public B
: >{
: > X() : V(5) {} // The requirement for X to call
: > // Vs constructor directly I
: > // understand and agree with.
: >};
: >I would be grateful for the views of others in this matter.
: >Do other people find this requirement as annoying as I do?
: >Thanks in advance.
: >Bryan.
: >--
: >Bryan Drew, Email: bdrew@hi-q.demon.co.uk
: >Hi-Q Systems Limited, Tel : +44 (0)1252-815035
: >Hi-Q House, Ancells Court, Fax : +44 (0)1252-815022
: >Fleet, Hants GU13 8UZ UK
Author: tony@online.tmx.com.au (Tony Cook)
Date: 1995/07/24 Raw View
John Max Skaller (maxtal@Physics.usyd.edu.au) wrote:
: In article <3u6mnq$bag@fsgm01.fnal.gov>,
: David Sachs <sachs@fnal.fnal.gov> wrote:
: >
: >I am annoyed that the standards committee waffled badly on handling
: >the default version of operator=. The proposed standard specifically
: >states, that the number of times a virtual base is copied can be
: >implmentation dependent.
: I agree. It's pretty bad. However, a virtual base
: shouldn't have any user data in it anyhow.
Doesn't basic_ios (or ios) contain user data?
--
Tony Cook - tony@online.tmx.com.au
100237.3425@compuserve.com
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/07/20 Raw View
>Bryan Drew <bdrew@hi-q.demon.co.uk> wrote:
>
>>Can someone please explain to me why, when inheriting a
>>base class virtually, all most derived classes must call
>>the constructor of the virtual base class, even those that
>>only contain a single instance of the base class.
Do you have any _other_ suggestion?
There are two possible rules: a virtual base is
initialised by itself, or, a virtual base is initialised
by the most derived class.
The best policy is: the virtual base has no data.
So it doesn't matter.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/07/20 Raw View
In article <3u6mnq$bag@fsgm01.fnal.gov>,
David Sachs <sachs@fnal.fnal.gov> wrote:
>
>I am annoyed that the standards committee waffled badly on handling
>the default version of operator=. The proposed standard specifically
>states, that the number of times a virtual base is copied can be
>implmentation dependent.
I agree. It's pretty bad. However, a virtual base
shouldn't have any user data in it anyhow.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: b91926@fsgm01.fnal.gov (David Sachs)
Date: 1995/07/21 Raw View
maxtal@Physics.usyd.edu.au (John Max Skaller) writes:
>In article <3u6mnq$bag@fsgm01.fnal.gov>,
>David Sachs <sachs@fnal.fnal.gov> wrote:
>>
>>I am annoyed that the standards committee waffled badly on handling
>>the default version of operator=. The proposed standard specifically
>>states, that the number of times a virtual base is copied can be
>>implmentation dependent.
> I agree. It's pretty bad. However, a virtual base
>shouldn't have any user data in it anyhow.
I do feel that a virtual base should normally be initialized via its
default constructor. This does NOT mean that it should have no data
whatsoever.
--
** The Klingons' favorite food was named by the first earthling to see it **
David Sachs - Fermilab, HPPC MS369 - P. O. Box 500 - Batavia, IL 60510
Voice: 1 708 840 3942 Deparment Fax: 1 708 840 3785
Author: shashank@sashimi.wwa.com (Shashaanka)
Date: 1995/07/19 Raw View
Please Read ARM. You will get your answer.
Bryan Drew <bdrew@hi-q.demon.co.uk> wrote:
>Can someone please explain to me why, when inheriting a
>base class virtually, all most derived classes must call
>the constructor of the virtual base class, even those that
>only contain a single instance of the base class.
>Taking the inheritance lattice:
> C X
> \ / \
> \ / \
> \ / \
> \ / \
> A B
> \ /
> \ /
> \ /
> \ /
> V
>I can understand that class X needs to call V's constructor
>directly because the compiler is unable to determine
>whether to use the constructor behaviour defined by A or B
>in order to initialise V.
>However, the language also requires class C to call V's
>constructor, even though using A's constructor behaviour to
>initialise V in this case is both logical and unambiguous.
>The problem is further exacerbated if further derivations
>are made from C, each new specialisation having to
>redeclare the redundant construction of V.
>Is there any real reason for this, or is it there just to
>make the life of compiler writers easier ?
>A code example follows:
>class V
>{
> private:
> const int i;
> public:
> V( const int in_i) : z(in_z) {}
>};
>class A : public virtual V
>{
> A() : V(3) {}
>};
>class B : public virtual V
>{
> B() : V(5) {}
>};
>class C : public A
>{
> C() {} // Why must this be illegal ?
> // Surely the constuction of V
> // is unambiguous due to single
> // inheritance through A.
>};
>class X : public A, public B
>{
> X() : V(5) {} // The requirement for X to call
> // Vs constructor directly I
> // understand and agree with.
>};
>I would be grateful for the views of others in this matter.
>Do other people find this requirement as annoying as I do?
>Thanks in advance.
>Bryan.
>--
>Bryan Drew, Email: bdrew@hi-q.demon.co.uk
>Hi-Q Systems Limited, Tel : +44 (0)1252-815035
>Hi-Q House, Ancells Court, Fax : +44 (0)1252-815022
>Fleet, Hants GU13 8UZ UK
Author: shashank@sashimi.wwa.com (Shashaanka)
Date: 1995/07/19 Raw View
Please Read ARM. You will get your answer.
Bryan Drew <bdrew@hi-q.demon.co.uk> wrote:
>Can someone please explain to me why, when inheriting a
>base class virtually, all most derived classes must call
>the constructor of the virtual base class, even those that
>only contain a single instance of the base class.
>Taking the inheritance lattice:
> C X
> \ / \
> \ / \
> \ / \
> \ / \
> A B
> \ /
> \ /
> \ /
> \ /
> V
>I can understand that class X needs to call V's constructor
>directly because the compiler is unable to determine
>whether to use the constructor behaviour defined by A or B
>in order to initialise V.
>However, the language also requires class C to call V's
>constructor, even though using A's constructor behaviour to
>initialise V in this case is both logical and unambiguous.
>The problem is further exacerbated if further derivations
>are made from C, each new specialisation having to
>redeclare the redundant construction of V.
>Is there any real reason for this, or is it there just to
>make the life of compiler writers easier ?
>A code example follows:
>class V
>{
> private:
> const int i;
> public:
> V( const int in_i) : z(in_z) {}
>};
>class A : public virtual V
>{
> A() : V(3) {}
>};
>class B : public virtual V
>{
> B() : V(5) {}
>};
>class C : public A
>{
> C() {} // Why must this be illegal ?
> // Surely the constuction of V
> // is unambiguous due to single
> // inheritance through A.
>};
>class X : public A, public B
>{
> X() : V(5) {} // The requirement for X to call
> // Vs constructor directly I
> // understand and agree with.
>};
>I would be grateful for the views of others in this matter.
>Do other people find this requirement as annoying as I do?
>Thanks in advance.
>Bryan.
>--
>Bryan Drew, Email: bdrew@hi-q.demon.co.uk
>Hi-Q Systems Limited, Tel : +44 (0)1252-815035
>Hi-Q House, Ancells Court, Fax : +44 (0)1252-815022
>Fleet, Hants GU13 8UZ UK
Author: Bryan Drew <bdrew@hi-q.demon.co.uk>
Date: 1995/07/13 Raw View
Can someone please explain to me why, when inheriting a
base class virtually, all most derived classes must call
the constructor of the virtual base class, even those that
only contain a single instance of the base class.
Taking the inheritance lattice:
C X
\ / \
\ / \
\ / \
\ / \
A B
\ /
\ /
\ /
\ /
V
I can understand that class X needs to call V's constructor
directly because the compiler is unable to determine
whether to use the constructor behaviour defined by A or B
in order to initialise V.
However, the language also requires class C to call V's
constructor, even though using A's constructor behaviour to
initialise V in this case is both logical and unambiguous.
The problem is further exacerbated if further derivations
are made from C, each new specialisation having to
redeclare the redundant construction of V.
Is there any real reason for this, or is it there just to
make the life of compiler writers easier ?
A code example follows:
class V
{
private:
const int i;
public:
V( const int in_i) : z(in_z) {}
};
class A : public virtual V
{
A() : V(3) {}
};
class B : public virtual V
{
B() : V(5) {}
};
class C : public A
{
C() {} // Why must this be illegal ?
// Surely the constuction of V
// is unambiguous due to single
// inheritance through A.
};
class X : public A, public B
{
X() : V(5) {} // The requirement for X to call
// Vs constructor directly I
// understand and agree with.
};
I would be grateful for the views of others in this matter.
Do other people find this requirement as annoying as I do?
Thanks in advance.
Bryan.
--
Bryan Drew, Email: bdrew@hi-q.demon.co.uk
Hi-Q Systems Limited, Tel : +44 (0)1252-815035
Hi-Q House, Ancells Court, Fax : +44 (0)1252-815022
Fleet, Hants GU13 8UZ UK
Author: raines@esaw01.SLAC.Stanford.EDU (Paul E. Raines)
Date: 1995/07/14 Raw View
In article <648258751wnr@hi-q.demon.co.uk> Bryan Drew <bdrew@hi-q.demon.co.uk> writes:
>> Can someone please explain to me why, when inheriting a
>> base class virtually, all most derived classes must call
>> the constructor of the virtual base class, even those that
>> only contain a single instance of the base class.
>>
>> [ ... stuff deleted ... ]
>>
>> I would be grateful for the views of others in this matter.
>> Do other people find this requirement as annoying as I do?
>>
Yes! Absolutely yes! Very annoying. It makes the virtual base classes useless
in C++, IMHO. I would go so far as to say in the following lattice
Y
|
|
|
|
|
X
/ \
/ \
/ \
/ \
A B
\ /
\ /
\ /
\ /
V
that it seems ridiculous that Y must also call V's constructor explicitly
instead of letting X handle the detail. Seems to throw the ideals of reusability
and abstraction out the window.
pr
--
_________________________________________________________________________
Paul Raines raines@slac.stanford.edu 415-926-4378
Stanford Linear Accelerator End Station A E143 Collaboration
http://www.slac.stanford.edu/~raines/index.html PGP public key by finger
Author: b91926@fsgm01.fnal.gov (David Sachs)
Date: 1995/07/14 Raw View
One excuse for requiring a derived class to initialize all virtual
bases, is that this simplifies using the class as a base class. In
most cases I have seen, virtual bases are initialized with a default
constructor, so the question of when they are initialized is handled
behind the scene.
I am annoyed that the standards committee waffled badly on handling
the default version of operator=. The proposed standard specifically
states, that the number of times a virtual base is copied can be
implmentation dependent.
--
** The Klingons' favorite food was named by the first earthling to see it **
David Sachs - Fermilab, HPPC MS369 - P. O. Box 500 - Batavia, IL 60510
Voice: 1 708 840 3942 Deparment Fax: 1 708 840 3785