virtual inheritance question

  • Thread starter Thread starter Bruno van Dooren
  • Start date Start date
B

Bruno van Dooren

Hi all,

i am having a problems with inheritance.
consider the following:

class A
{
public:
A(int i){;}
};

class B: virtual public A
{
public:
B(int i) : A(i){;}
};

class C: virtual public B
{
public:
C(int i) : B(i){;} //raises error C2512: 'A::A' : no appropriate
default constructor available
};

can someone tell me why i get that error? it has to do with the fact that B
has virtual inheritance from A. if i make that non-virtual, the error is
gone. what is the impact of the 'virtual' keyword in this situation?

kind regards,
Bruno.
 
Bruno said:
Hi all,

i am having a problems with inheritance.
consider the following:

class A
{
public:
A(int i){;}
};

class B: virtual public A
{
public:
B(int i) : A(i){;}
};

class C: virtual public B
{
public:
C(int i) : B(i){;} //raises error C2512: 'A::A' : no appropriate
default constructor available
};

can someone tell me why i get that error? it has to do with the fact that B
has virtual inheritance from A. if i make that non-virtual, the error is
gone. what is the impact of the 'virtual' keyword in this situation?

When you use virtual inheritence, you need to initialize each virtual
base class in the most derived class constructor, since you might have
multiple bases that would do the initialisation if this wasn't the case
(e.g. the classic diamond virtual inheritance example). So your C class
constructor needs to initialize the A base object as well as the B one -
B's initialization of A is ignored when creating a C object.

Tom
 
(e.g. the classic diamond virtual inheritance example). So your C class
constructor needs to initialize the A base object as well as the B one -
B's initialization of A is ignored when creating a C object.

Tom

thanks. however, this has the followig implications:
please consider a new scenario:

class A
{
public:
A(int i){;}
};

class B: virtual public A
{
public:
B(int i) : A(i){;}
};

class C: virtual public A
{
public:
C(int i) : A(i){;}
};

class D: virtual public B, C
{
public:
D(int i): C(i),B(i),A(i){;}
};

in this case i end up with C and B using the same instance of A.
multiple inheritance is the only scenario in which i can see a use for
virtual inheritance.
looking at it like this, it seems that the only use of the 'virtual' keyword
in inheritance context is to say "whoever inherits from me has to initialize
my base class too"

this meaning seems unrelated to the meaning of virtual in the context of
member functions. is that correct?

kind regards,
Bruno.
 
Bruno said:
thanks. however, this has the followig implications:
please consider a new scenario:

class A
{
public:
A(int i){;}
};

class B: virtual public A
{
public:
B(int i) : A(i){;}
};

class C: virtual public A
{
public:
C(int i) : A(i){;}
};

class D: virtual public B, C
{
public:
D(int i): C(i),B(i),A(i){;}
};

in this case i end up with C and B using the same instance of A.
multiple inheritance is the only scenario in which i can see a use for
virtual inheritance.

I'd agree with that statement.
looking at it like this, it seems that the only use of the 'virtual'
keyword in inheritance context is to say "whoever inherits from me
has to initialize my base class too"

It does imply that, yes.
this meaning seems unrelated to the meaning of virtual in the context
of member functions. is that correct?

Mostly unrelated - they just re-used the keyword rather than coming up with
yet another one. The way virtual base classes are implemented is not
dissimilar to how virtual functions are implemented, however. Classes that
have virtual bases have a virtual base table, just like they have a virtual
function table. The entries in the virtual base table gives the offset from
the start of the complete object to the corresponding virtual base.

-cd
 
Bruno said:
thanks. however, this has the followig implications:
please consider a new scenario:

class A
{
public:
A(int i){;}
};

class B: virtual public A
{
public:
B(int i) : A(i){;}
};

class C: virtual public A
{
public:
C(int i) : A(i){;}
};

class D: virtual public B, C
{
public:
D(int i): C(i),B(i),A(i){;}
};

in this case i end up with C and B using the same instance of A.

.... when they are subobjects of a D. That's the classic diamond
inheritance example I mentioned. When you create a D object, only D's
initialization of A is used.
multiple inheritance is the only scenario in which i can see a use for
virtual inheritance.

looking at it like this, it seems that the only use of the 'virtual' keyword
in inheritance context is to say "whoever inherits from me has to initialize
my base class too"

For single inheritance, yes - virtual inheritance is really for cases
where multiple inheritance is, or may be in the future, employed. The
standard library uses it for the ios base class of istream and ostream,
to ensure that iostream only has one ios subobject (basic_ prefixes
elided for clarity).
this meaning seems unrelated to the meaning of virtual in the context of
member functions. is that correct?

Yes.

Tom
 
Carl said:
Mostly unrelated - they just re-used the keyword rather than coming up with
yet another one. The way virtual base classes are implemented is not
dissimilar to how virtual functions are implemented, however. Classes that
have virtual bases have a virtual base table, just like they have a virtual
function table. The entries in the virtual base table gives the offset from
the start of the complete object to the corresponding virtual base.

Nonetheless, I find it was a mistake to reuse the same keyword for
something completely different, even if the inner implementation guts
may have some vague relation. One more time, the
"do-not-add-a-new-keyword-for-any-reason-even-a-very-good-one" syndrom
has bitten us!

Arnaud
MVP -VC
 
Nonetheless, I find it was a mistake to reuse the same keyword for
something completely different, even if the inner implementation guts
may have some vague relation. One more time, the
"do-not-add-a-new-keyword-for-any-reason-even-a-very-good-one" syndrom
has bitten us!

Arnaud
MVP -VC

I had the same feeling, but not the audacity of venting this opinion on a
public forum because i am obviously not a C++ guru or an MVP.
I feel good knowing that i am not alone in this opinion.

we might as well throw every means of transportation on wheels out of the
dictionary and call everything a bycicle:
car == bycicle with 4 wheels and an engine.
moto bike = bycicle with an engine
train == bicyle with lots of wheels, a heavy duty engine, drives on a
predefined track.
....
 
this meaning seems unrelated to the meaning of virtual in the
context


Nonetheless, I find it was a mistake to reuse the same keyword for
something completely different, even if the inner implementation guts
may have some vague relation. One more time, the
"do-not-add-a-new-keyword-for-any-reason-even-a-very-good-one" syndrom
has bitten us!

In fact, a virtual base class relates to a base class the same way,
as a virtual member function relates to a non-virtual member function.

You can override implementation of a virtual base class in the derived
class.
Often virtual base classes contain pure member functions only.
These member functions are overriden in descendants.
This way you are achieving a construction called interface.
 
Vladimir said:
In fact, a virtual base class relates to a base class the same way,
as a virtual member function relates to a non-virtual member function.

You can override implementation of a virtual base class in the derived
class.

Nonsense - there's no such thing as overriding a virutal base class.
Often virtual base classes contain pure member functions only.
These member functions are overriden in descendants.

In which case you're simply overriding virtual functions declared in the
base class (which happens to be virtual). Any non-virtual members in the
virtual base class are still there and cannot be overridden.
This way you are achieving a construction called interface.

Which you can do just fine without the use of virtual base classes (see COM,
for example).

-cd
 
In fact, a virtual base class relates to a base class the same way,
Nonsense - there's no such thing as overriding a virutal base class.

struct A
{
virtual void f() { std::cout << "struct A" << std::endl; }
virtual void f2() { std::cout << "struct A" << std::endl; }
};

struct B: public virtual A
{
virtual void f() { std::cout << "struct B" << std::endl; }
virtual void f2() { std::cout << "struct B" << std::endl; }
};

struct C: public virtual A {};

struct D: public C, public virtual B {};

int main()
{
C &c1 = C();
C &c2 = D();

c1.f();
c2.f();
}

From these declarations we can see that ? contains A as its part, however B
substitutes A in the D.
In this sence B overrides A in the D, which is descendant of the C.
In which case you're simply overriding virtual functions declared in the
base class (which happens to be virtual). Any non-virtual members in the
virtual base class are still there and cannot be overridden.


Which you can do just fine without the use of virtual base classes (see COM,
for example).

In fact .NET interfaces are closer to a virtual pure base classes than to
other model.
 
Vladimir said:
In fact, a virtual base class relates to a base class the same way,
as a virtual member function relates to a non-virtual member function.

You can override implementation of a virtual base class in the derived
class.
Often virtual base classes contain pure member functions only.
These member functions are overriden in descendants.
This way you are achieving a construction called interface.

On the contrary, virtual inheritance make sense only for base classes that
are not pure interfaces : the whole point of VI is to avoid duplication of
data members : on a pure interface, you've got no data members, so no
duplicates problems. The other effects you may see on function is
side-effect of the "overiding through dominance" rule, but this not the
purpose of VI.

Note that things can become a bit messy when you add delegates/events to the
big picture. For example, I often declare C++ "interfaces" (no
implementation and no "logical" data member) that contain one or more
boost::signal (or LibSigC++ equivalent), because I do consider that the
events that can be raisen are part of an interface. However, this make my
"logical" interfaces physical "classes" (with data members). In such a case,
VI has a meaning even for interfaces, but this is more a deficiency of the
C++ model (lack of events/delegates/closures) than anything else.

Arnaud
MVP - VC
 
[snipped to save space]
From these declarations we can see that ? contains A as its part, however
B
substitutes A in the D.
In this sence B overrides A in the D, which is descendant of the C.

Not so. B overrides the functions originally declared in A, it does not
override A itself. If your virtual base contains only pure virtual
functions, there's no practical difference. It's when your virtual base
contains data members that the distinction is important.

-cd
 
In fact, a virtual base class relates to a base class the same way,
Not so. B overrides the functions originally declared in A, it does not
override A itself. If your virtual base contains only pure virtual
functions, there's no practical difference. It's when your virtual base
contains data members that the distinction is important.

This way one can argue that virtual member functions are not overriden
indeed, but only some values in virtual tables are substituted, and old
implementations are in their places.

If the struct A contains a state and this state is changed in a constructor
of the struct B, or extended in a declaration of the struct B, than other
subobjects see subobject A after its initialization with the struct B. In
this sence B overrides A's state.
 
On the contrary, virtual inheritance make sense only for base classes that
are not pure interfaces

I do not agree with such a categorical assertion.
The whole idea of interfaces in com, java, .net is close to a virtual
inheritance of a pure classes.
 
Vladimir said:
This way one can argue that virtual member functions are not overriden
indeed, but only some values in virtual tables are substituted, and
old implementations are in their places.

If the struct A contains a state and this state is changed in a
constructor of the struct B, or extended in a declaration of the
struct B, than other subobjects see subobject A after its
initialization with the struct B. In this sence B overrides A's state.

In C++, the term "overriding" has a well-defined technical meaning. It
applies exclusively to member functions. There is no such thing as
overriding of a class.

--
Gerhard Menzl

#dogma int main ()

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