C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Virtual inheritance

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Giulio Guarnone
Guest





PostPosted: Wed Aug 24, 2005 9:29 am    Post subject: Virtual inheritance Reply with quote



Hi,

I'm trying to study C++ a little deeper.

During my reading I've found "virtual inheritance" : sounds cool but I
haven't understood very the arguments.

May someone explain me when and why I'd prefer virtual to "simple"
inheritance ?
Is that really useful in real world ?

Thanks,
Giulio

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

Back to top
kwikius
Guest





PostPosted: Wed Aug 24, 2005 12:45 pm    Post subject: Re: Virtual inheritance Reply with quote



Giulio Guarnone wrote:
Quote:
Hi,

I'm trying to study C++ a little deeper.

During my reading I've found "virtual inheritance" : sounds cool but I
haven't understood very the arguments.

May someone explain me when and why I'd prefer virtual to "simple"
inheritance ?

Typical use is as follows:

#include <vector>
#include <iostream>

// abstract base class for calculations.
//( pure virtual functions signified by "=0")

struct calc_node{
virtual double eval()const =0;
virtual std::ostream& print(std::ostream& os)const =0;
virtual ~calc_node(){}
};

// various actual calculations derived from calc_node
// which store their operands
// ready for evaluation
// Implement the pure virtual functions declared in calc_node

struct add : public calc_node
{
double const a,b;
add (double const & a_in, double const & b_in):a(a_in),b(b_in){}
double eval()const
{
return a + b;
}
std::ostream& print(std::ostream& os)const
{
os << a << " + " << b;
return os;
}
};
struct subtract : public calc_node
{
double const a,b;
subtract (double const & a_in, double const &
b_in):a(a_in),b(b_in){}
double eval() const
{
return a - b;
}
std::ostream& print(std::ostream& os)const
{
os << a << " - " << b;
return os;
}

};
struct increment : public calc_node
{
double const a;
increment (double const & a_in):a(a_in){}
double eval() const
{
return a+1;
}
std::ostream& print(std::ostream& os)const
{
os << a << " + 1";
return os;
}
};


int main()
{
// Typically calc_nodes are stored in a container
std::vector
// various actual calc_nodes can be added

calcs.push_back(new add(1.,2.));
calcs.push_back(new subtract(2.,1.));
calcs.push_back(new increment(1.));

// iterate through the container
// without caring about the exact type of
// calc_node we are dealing with
typedef std::vector<calc_node*>::const_iterator citer;
for( citer i = calcs.begin(); i != calcs.end(); ++i){
calc_node const * n = *i;
n->print(std::cout) << " = " << n->eval() << 'n';
}



// ( clean up )
typedef std::vector for( iter i = calcs.begin(), i != calcs.end(); ++i){
delete *i;
}

}

regards
Andy Little


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


Back to top
Filip.STOKLAS@gmail.com
Guest





PostPosted: Wed Aug 24, 2005 2:54 pm    Post subject: Re: Virtual inheritance Reply with quote



It is useful in the case of multiple inheritance to avoid the
duplicated base class subobject (this eliminates the ambiguities).

look at:
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html

________________________________________________
+++ Filip STOKLAS (FipS), www.FS-Games.com/FipS/


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

Back to top
tony_in_da_uk@yahoo.co.uk
Guest





PostPosted: Wed Aug 24, 2005 2:59 pm    Post subject: Re: Virtual inheritance Reply with quote

Say you wanted some classes to keep an event history: whichever
functions thought they were doing some miraculous could push_back a
timestamped string. You might reasonably factor the behaviour into a
base class, say "Event_History". Now, if you're using multiple
inheritance to create a new class that uses two classes derived from
Event_History, there will be times when you don't care about the
inheritance heirarchy, and just want the newly derived class to have a
single consolidated Event_History. This is automatically achieved by
making the Event_History derivation virtual.

Virtual inheritance is also useful in hierarchies modelling graphical
elements where properties are to apply to elements created by multiple
inheritance (e.g. a drop-down box might want a shared idea of
background and foreground colour, and not need to model independent
settings for each rectangle, line, shaded area, polygon or whatever
used in its derivation. The way in which more complicated graphical
elements can usefully have a single set of common data members is very
evident even in non-C++ systems like Tcl/Tk.

Cheers,

Tony


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

Back to top
Frank Chang
Guest





PostPosted: Wed Aug 24, 2005 3:02 pm    Post subject: Re: Virtual inheritance Reply with quote

Andy, Virtual inheritance is used to avoid multiple copies of a base
class in a mutiple inheritance derivation. Is that what you trying to
show with your code examples? Thank you.


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

Back to top
Frank Chang
Guest





PostPosted: Wed Aug 24, 2005 3:10 pm    Post subject: Re: Virtual inheritance Reply with quote

Giulio, Please see the links
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.11


and

http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.8


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

Back to top
benben
Guest





PostPosted: Wed Aug 24, 2005 3:10 pm    Post subject: Re: Virtual inheritance Reply with quote


"Giulio Guarnone" <genghis.khan (AT) tiscali (DOT) it> wrote

Quote:
Hi,

I'm trying to study C++ a little deeper.

During my reading I've found "virtual inheritance" : sounds cool but I
haven't understood very the arguments.

May someone explain me when and why I'd prefer virtual to "simple"
inheritance ?
Is that really useful in real world ?

Thanks,
Giulio

You use virtual inheritance when multiple copies of a base class subobject
is undesirable. Consider an imaginary garbage collector, which only collects
object of types compatible to class gc_base. In other words, only classes
that inherits gc_base should be subject to garbage collection:

class gc_base;

class fruit: public gc_base
{
// fruit is collectable
};

class apple: public fruit
{
// apple is collectable
};

Now, keep in mind that the garbage collector collects only gc_base objects,
consider the following case:

class genetically_modified: public gc_base
{
// ...
};

class gm_apple:
public apple,
public genetically_modified
{
// ...
};

The class gm_apple inherits from both apple and genetically_modified. And
because each base inherits from gc_base, a gm_apple object ends up
accomodating two gc_base subobjects. Unfortunately, the collecting mechanism
doesn't recognize the design of gm_apple and would collect any gm_apple
object twice, each for a bc_base subobject.

To remedy, we must inforce that any collectable object must accomodate one
and only one gc_base subobject. This can be done by requiring collectable
classes to virtually inherite from gc_base. Our example becomes:

class gc_base; // meant to be inherited virtually

class fruit: public virtual gc_base
{
// ...
};

class apple: public fruit
{
// ...
}

class genetically_modified: public virtual gc_base
{
// ...
};

class gm_apple:
public apple,
public genetically_modified
{
// only one gc_base subobject
};


Regards,
Ben



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


Back to top
Hyman Rosen
Guest





PostPosted: Wed Aug 24, 2005 10:22 pm    Post subject: Re: Virtual inheritance Reply with quote

Giulio Guarnone wrote:
Quote:
May someone explain me when and why I'd prefer virtual to "simple"
inheritance ? Is that really useful in real world ?

Virtual inheritance in C++ plays a role akin to extending interfaces
in Java. Let's begin with an example there:
interface iA { void f(); }
interface iB extends iA { void g(); }
class cB implements iB { void f(){} void g(){} }
interface iC extends iA { void h(); }
class cD extends cB implements iC { void h(){} }
... { cD d = new cD; d.f(); d.g(); d.h(); }
How would you write this in C++? Naively, let's try:
struct iA { virtual void f() = 0; };
struct iB : iA { virtual void g() = 0; };
struct cB : iB { void f(){} void g(){} };
struct iC : iA { virtual void h() = 0; };
struct cD : cB, iC { void h(){} };
int main() { cD d; d.f(); d.g(); d.h(); }
You will discover that this does not compile - the compiler
will complain that cD is an abstract class, and also that
the call to d.f() is ambiguous. This is because in C++, there
is a separate iA part in iB and iC, and the f() in iC::A has
not been overridden, rendering the class abstract. In C++,
you fix this with virtual inheritance on the interface classes:
struct iA { virtual void f() = 0; };
struct iB : virtual iA { virtual void g() = 0; };
struct cB : virtual iB { void f(){} void g(){} };
struct iC : virtual iA { virtual void h() = 0; };
struct cD : cB, virtual iC { void h(){} };
int main() { cD d; d.f(); d.g(); d.h(); }
Now there is only a single iA in the class, and the overrider
in cB serves to make the class non-abstract.

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


Back to top
srez
Guest





PostPosted: Wed Aug 24, 2005 10:25 pm    Post subject: Re: Virtual inheritance Reply with quote

Giulio,

Quote:
I'm trying to study C++ a little deeper.

During my reading I've found "virtual inheritance" : sounds cool but I
haven't understood very the arguments.

Here is why this type of inheritance is called virtual:

#include <iostream>
using std::cout;
using std::endl;

class Base {
public:
Base( const char* msg ) : msg_( msg ) {}

const char* getMessage() { return msg_; }
private:
const char* msg_;
};

class A : public virtual Base {
public:
A() : Base( "A class" ) {}
};

class B : public virtual Base {
public:
B() : Base( "B class" ) {}
};


class MostDerived : public A, public B {
public:
MostDerived() : Base( "MostDerived class" ) {}
};


int main()
{
MostDerived obj;
cout << obj.getMessage() << endl;
}

This program outputs "MostDerived class". So the constructor of virtual
base class looks like a virtual function in some sense: you can
override the behavior in (even not direct) descendants.

Regards,
srez


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


Back to top
Frank Chang
Guest





PostPosted: Wed Aug 24, 2005 10:25 pm    Post subject: Re: Virtual inheritance Reply with quote

Tony, There is another application of virtual inheritance. Please see
the threads in the group about how to implement a C++ clas that cannot
be inherited from. However, There are some performance penalties with
using virtual inheritance. James Kanze states,

"Navigating a class hierarchy which used virtual bases
is significantly slower than navigating one that doesn't, and classes
using virtual inheritance are often significantly bigger than those
that don't. This largely depends on the compiler, of course."

Also , Scott Meyers in "Effective C++" mentions the time and space
penalties of using virtual inheritance. Evidently , some compilers
implement virtual inheritance by adding a pointer in objects of the
derived class.


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

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Aug 25, 2005 11:05 pm    Post subject: Re: Virtual inheritance Reply with quote

Frank Chang wrote:
Quote:
Tony, There is another application of virtual
inheritance. Please see the threads in the group about how to
implement a C++ clas that cannot be inherited from. However,
There are some performance penalties with using virtual
inheritance. James Kanze states,

"Navigating a class hierarchy which used virtual bases is
significantly slower than navigating one that doesn't, and
classes using virtual inheritance are often significantly
bigger than those that don't. This largely depends on the
compiler, of course."

It would be interesting to know when I stated this. Ten or more
years ago, the space cost of virtual inheritance was enormous
for some compilers -- in one actual hierarchy, we found that one
compiler would use 10 or more times more memory than another for
the same hierarchy.

(In fact, there was a bug in one of the compilers: it reserved
space for the data of the virtual base data in every class that
derived from the virtual base, which it never used. Since the
compiler in question was CFront, which was by far the most
widespread C++ compiler at the time, virtual inheritance
acquired a particularly bad reputation with regards to space
overhead.)

Today, the worst implementations have pretty much disappeared.
There's still some overhead, but it's not necessarily
exhorbitant.

Quote:
Also , Scott Meyers in "Effective C++" mentions the time and
space penalties of using virtual inheritance. Evidently ,
some compilers implement virtual inheritance by adding a
pointer in objects of the derived class.

The basic problem is that given a hierarchy like:

VB
/
L R
/
D

where L and R derive virtually from VB, the compiler cannot
know, when laying out L, R or even D, where VB will be situated
relative to the derived class in question. The classical
solution to this problem was to add a pointer to VB to each of
the derived classes, and use this pointer when upcasting. This,
of course, has both a space and a runtime overhead. Most modern
compilers, I believe, put the information in the vtable (in the
form of an offset), and generate some sort of trampoline code
for navigation -- the space overhead thus becomes dependant on
the number of classes, and not the number of objects, and
typically, the runtime overhead is also lessened. Things like
dynamic_cast may still be significantly slower, but while the
additional runtime overhead involved in calling a virtual
function is not necessarily negligible, it is considerably
smaller than in earlier implementations.

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


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


Back to top
Giulio Guarnone
Guest





PostPosted: Thu Aug 25, 2005 11:07 pm    Post subject: Re: Virtual inheritance Reply with quote

Hyman Rosen ha scritto:

Quote:
This is because in C++, there is a separate iA part in iB and iC, and the f() in iC::A has
not been overridden, rendering the class abstract.
[...]
struct iA { virtual void f() = 0; };
struct iB : virtual iA { virtual void g() = 0; };
struct cB : virtual iB { void f(){} void g(){} };
struct iC : virtual iA { virtual void h() = 0; };
struct cD : cB, virtual iC { void h(){} };
int main() { cD d; d.f(); d.g(); d.h(); }
Now there is only a single iA in the class, and the overrider
in cB serves to make the class non-abstract.

I'm sure if I understand :

Is this like iB and iC share the same iA part ?
A single vtable entry for f() ?

Thanx,
Giulio

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


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Fri Aug 26, 2005 9:51 am    Post subject: Re: Virtual inheritance Reply with quote

Giulio Guarnone wrote:
Quote:
Hyman Rosen ha scritto:

This is because in C++, there is a separate iA part in iB
and iC, and the f() in iC::A has not been overridden,
rendering the class abstract.
[...]
struct iA { virtual void f() = 0; };
struct iB : virtual iA { virtual void g() = 0; };
struct cB : virtual iB { void f(){} void g(){} };
struct iC : virtual iA { virtual void h() = 0; };
struct cD : cB, virtual iC { void h(){} };
int main() { cD d; d.f(); d.g(); d.h(); }
Now there is only a single iA in the class, and the overrider
in cB serves to make the class non-abstract.

I'm sure if I understand :

Is this like iB and iC share the same iA part ?

Correct.

Quote:
A single vtable entry for f() ?

It might be clearer using data members:

struct B { int b ; } ;
struct L : virtual B { int l ; } ;
struct R : virtual B { int r ; } ;
struct D : L, R { int d ; } ;

In D, there is exactly one instance of B, and fonctions in L or
R will share the same B::b. Without the virtual, L and R would
each have their own instance of B::b.

Note that this also affects casting. Given the above, with
virtual inheritance,
B* pB = new D ;
is legal. Without virtual inheritance, it wouldn't be, since
there would be two B subobjects (with different addresses), and
the compiler wouldn't know which one to use. (Note that this is
the main reason why you need virtual inheritance, even if the
base class is empty.)

In the case of functions: regardless of where f() is called, the
actual function called will be cB::f(). Even if it were called
from a function in iC, and despite the fact that iC doesn't
inherit from cB. Consider a simpler example:

struct B { virtual void f() = 0 ; virtual void g() = 0 ; } ;
struct L : virtual B { virtual void f() ; } ;
struct R : virtual B { virtual void g() ; } ;
struct D : L, R {} ;

Calling f() from R::g() (in an object of type D) will call
L::f(), despite the fact that L is neither a base of nor derives
from R. Without virtual inheritance, you couldn't instantiate
D, since there is no override for the g() in L's B nor for the
f() in R's B.

The classic way of presenting this is with a diagram:

with virtual inheritance:

B
/
R L
/
D

without:

B B
/
R L
/
D

Most of the time, the first lattice (the diamond) is to be
preferred, and arguably, inheritance should be virtual by
default. Virtual inheritance is, however, significantly more
expensive than simple inheritance, and there are a lot of
hierarchies which only use single inheritance, and would pay the
run-time penalty for virtual inheritance even though they don't
need it. So the rule "you don't pay for what you don't need"
means that virtual inheritance isn't the default.

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


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


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.