Since C++ is missing the "interface" concept present in Java, I've been using
the following pattern to simulate its behavior:
class Interface0
{
public:
virtual void fn0() = 0;
};
class Interface1
{
public:
virtual void fn1() = 0;
};
class Implementation0: public virtual Interface0, // note "public virtual"
public virtual Interface1
{
public:
virtual void fn0(); // implementation
virtual void fn1(); // implementation
/* ... */
};
I have consistently used public virtual inheritance whenever I'm implementing
(or extending) an interface, to ensure that there is only one instance of the
interface present in any class hierarchy.
Using virtual inheritance also allows me to create mixin classes. For example:
class DefaultInterface0Implementation : public virtual Interface0
{
public:
virtual void fn0(); // implementation
};
class Implementation1: public virtual Interface0,
public virtual Interface1,
private DefaultInterface0Implementation // mixin
{
public:
virtual void fn1(); // implementation
using DefaultInterface0Implementation::fn0(); // mixin behavior
/* ... */
};
This pattern has been successfully used in several projects.
Still, I can't help thinking that this pattern is overkill. Really, the only
time virtual inheritance is needed is when mixins are used (always at the
terminal implementation class definition). Virtual inheritance also costs time
(extra pointer indirection and construction sequence) and space (extra pointer
storage per object) at runtime. For objects that implement a handful of
interfaces, but maintain very little state, the added pointer storage can
represent 20-50% of the storage requirements.
There is also the side effect of not being able to downcast from a pointer to
an interface. However, I've found that with good OO design this is almost
never an issue (hint: serialization can be performed through a Serializable
interface).
Then why not select which interfaces to virtually inherit from at the terminal
implementation class definition? Because interfaces can extend other
interfaces:
class Interface2 { /* ... */ };
class Interface2A: public virtual Interface2 { /* ... */ };
class Interface2Mixin: public virtual Interface2 { /* implementation */ };
class Implementation: public virtual Interface2A, private Interface2Mixin
{ /* ... */ };
This pattern forces Interface2A to virtually inherit from Interface2.
Not using virtual inheritance consistently also causes trouble when _new_
mixin classes are developed. When a new mixin class is defined for future use,
the developer must search for all classes that derive from a particular
interface, and change their inheritance relationship to virtual. This causes a
lot of unneccessary code churning.
Although the rules I use are "always correct" for my purposes, they may not be
the most efficient for real life.
Does anyone have a better set of rules that I can consider using?
-dr 23 4441
Dave Rahardja wrote:
Since C++ is missing the "interface" concept present in Java, I've been using
the following pattern to simulate its behavior:
class Interface0
{
public:
virtual void fn0() = 0;
};
class Interface1
{
public:
virtual void fn1() = 0;
};
class Implementation0: public virtual Interface0, // note "public virtual"
public virtual Interface1
{
public:
virtual void fn0(); // implementation
virtual void fn1(); // implementation
/* ... */
};
I have consistently used public virtual inheritance whenever I'm implementing
(or extending) an interface, to ensure that there is only one instance of the
interface present in any class hierarchy.
Using virtual inheritance also allows me to create mixin classes. For example:
class DefaultInterface0Implementation : public virtual Interface0
{
public:
virtual void fn0(); // implementation
};
class Implementation1: public virtual Interface0,
public virtual Interface1,
private DefaultInterface0Implementation // mixin
{
public:
virtual void fn1(); // implementation
using DefaultInterface0Implementation::fn0(); // mixin behavior
/* ... */
};
This pattern has been successfully used in several projects.
Still, I can't help thinking that this pattern is overkill. Really, the only
time virtual inheritance is needed is when mixins are used (always at the
terminal implementation class definition). Virtual inheritance also costs time
(extra pointer indirection and construction sequence) and space (extra pointer
storage per object) at runtime. For objects that implement a handful of
interfaces, but maintain very little state, the added pointer storage can
represent 20-50% of the storage requirements.
There is also the side effect of not being able to downcast from a pointer to
an interface. However, I've found that with good OO design this is almost
never an issue (hint: serialization can be performed through a Serializable
interface).
Then why not select which interfaces to virtually inherit from at the terminal
implementation class definition? Because interfaces can extend other
interfaces:
class Interface2 { /* ... */ };
class Interface2A: public virtual Interface2 { /* ... */ };
class Interface2Mixin: public virtual Interface2 { /* implementation */ };
class Implementation: public virtual Interface2A, private Interface2Mixin
{ /* ... */ };
This pattern forces Interface2A to virtually inherit from Interface2.
Not using virtual inheritance consistently also causes trouble when _new_
mixin classes are developed. When a new mixin class is defined for future use,
the developer must search for all classes that derive from a particular
interface, and change their inheritance relationship to virtual. This causes a
lot of unneccessary code churning.
Although the rules I use are "always correct" for my purposes, they may not be
the most efficient for real life.
Does anyone have a better set of rules that I can consider using?
-dr
Forgive me if I misunderstand what you are doing, but I don't see why
virtual inheritance is needed in any of your examples. In my
understanding, virtually inheriting from an interface (for purposes of
this thread interface is defined as a class containing nothing but pure
virtual functions) is somewhat pointless.
If a derived object winds up inheriting the same interface along
multiple paths, how does that matter? It shouldn't affect which
function gets called in a dynamic dispatch. Nor should it cause any
space overhead if your compiler optimizes empty base classes (common in
most compilers).
--
Alan Johnson
Alan Johnson wrote:
>
If a derived object winds up inheriting the same interface along
multiple paths, how does that matter?
It makes calls to a function that takes a reference to that interface
ambiguous.
--
-- Pete
Roundhouse Consulting, Ltd. ( www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." ( www.petebecker.com/tr1book)
On Wed, 31 Jan 2007 10:06:03 -0800, Alan Johnson <aw***@yahoo.comwrote:
>Forgive me if I misunderstand what you are doing, but I don't see why virtual inheritance is needed in any of your examples. In my understanding, virtually inheriting from an interface (for purposes of this thread interface is defined as a class containing nothing but pure virtual functions) is somewhat pointless.
Here's an example:
class Interface
{
public:
virtual void fn() = 0;
};
class Mixin: public Interface
{
public:
virtual void fn() {}
};
class Implementation: public Interface, private Mixin
{
public:
using Mixin::fn;
};
int main()
{
Implementation imp; // <- error, abstract class.
Interface* pi = &imp; // <- error, ambiguous.
}
The problem goes away when both Mixin and Implementation inherit virtually
from Interface.
>If a derived object winds up inheriting the same interface along multiple paths, how does that matter? It shouldn't affect which function gets called in a dynamic dispatch. Nor should it cause any space overhead if your compiler optimizes empty base classes (common in most compilers).
Although the compiler won't allocate space for the empty base classes (aside
from the vtable pointer), it cannot get rid of the extra pointer indirection.
Take this example:
class I { /* contains pure virtuals */ };
class A: public virtual I { /* implements some of I */ };
class B: public virtual I { /* implement rest of I */ };
class M { /* independent class */ };
class X: public M, public A { /* implements rest of I */ };
class Y: public A, private B {};
int main()
{
X x;
Y y;
A* pax = &x;
I* piax = pax;
A* pay = &y;
I* piay = pay;
}
In all cases, the compiler needs to find the data area (or at least the vtable
pointer) associated with I part of the object. Getting from a "pointer to A"
to a "pointer to I" cannot be achieved without indirection, because the
storage position of the A data area (or vtable pointer) relative to the I data
area (or vtable pointer) depends on what concrete class (X or Y) it happens to
be a part of.
-dr
"Dave Rahardja" wrote in message
Since C++ is missing the "interface" concept present in Java, I've been
using
the following pattern to simulate its behavior:
Dave,
Just mentioning that virtual inheritance is only usefull when an abstract
class is multiply inherited, that is shared, see The C++ Programming
Language, Stroustrup, 3rd ed., 15.2.4.
About the cost of virtual functions, see also: http://www.parashift.com/c++-faq-lit...functions.html
In my opinion this cost may be an issue only for very small objects.
Regards, Maarten.
On Jan 31, 8:46 am, Dave Rahardja <a...@me.comwrote:
Since C++ is missing the "interface" concept present in Java, I've been using
the following pattern to simulate its behavior:
class Interface0
{
public:
virtual void fn0() = 0;
};
class Interface1
{
public:
virtual void fn1() = 0;
};
class Implementation0: public virtual Interface0, // note "public virtual"
public virtual Interface1
{
public:
virtual void fn0(); // implementation
virtual void fn1(); // implementation
/* ... */
};
Two points:
1) It is typically a good idea to declare a virtual destructor in any
class you're planning on inheriting from. This would include your
interfaces.
2) I would also agree with Alan, that you don't need virtual
inheritance *unless* you are planning to inherit from the same thing
in multiple ways. I would suggest just using regular public
inheritance unless you actually need the virtual inheritance. Such an
approach would save some poor maintenance programmer a lot of head
scratching, and increase the probability that your code isn't broken
by subsequent modifications. One of the great dangers of life is when
a maintenance programmer decides - correctly or not - that you're full
of **** and that you throw in all kinds of things you don't need; in
such a case he/she will probably just go through and globally remove
all the virtual inheritance, including the one or two places you
really do need it. It is somewhat better to use what you need, so
that anyone reading your code and finding virtual inheritance will
stop and think 'hmmm, there must be a good reason for this, let me
tread lightly.'
Michael
On Wed, 31 Jan 2007 20:04:45 +0100, "Maarten Kronenburg"
<M.**********@inter.nl.netwrote:
> "Dave Rahardja" wrote in message
>Since C++ is missing the "interface" concept present in Java, I've been
using
>the following pattern to simulate its behavior:
Dave, Just mentioning that virtual inheritance is only usefull when an abstract class is multiply inherited, that is shared, see The C++ Programming Language, Stroustrup, 3rd ed., 15.2.4.
I know that. The problem is that I may not know _when_ an abstract class will
be multiply inherited from _in the future_.
>About the cost of virtual functions, see also: http://www.parashift.com/c++-faq-lit...functions.html In my opinion this cost may be an issue only for very small objects.
I'm not concerned about the cost of virtual functions. I'm concerned about the
cost of virtual inheritance.
-dr
On 31 Jan 2007 11:16:31 -0800, "Michael" <mc******@aol.comwrote:
>On Jan 31, 8:46 am, Dave Rahardja <a...@me.comwrote:
>Since C++ is missing the "interface" concept present in Java, I've been using the following pattern to simulate its behavior:
class Interface0 { public: virtual void fn0() = 0;
};
class Interface1 { public: virtual void fn1() = 0;
};
class Implementation0: public virtual Interface0, // note "public virtual" public virtual Interface1 { public: virtual void fn0(); // implementation virtual void fn1(); // implementation /* ... */
};
Two points: 1) It is typically a good idea to declare a virtual destructor in any class you're planning on inheriting from. This would include your interfaces.
Only if you plan on destroying objects through those interfaces. But point
taken. Maybe interfaces should have the following format by default:
class Interface
{
public:
virtual void fn() = 0; // etc
private:
~Interface();
};
....which will prevent destruction through the interface.
>2) I would also agree with Alan, that you don't need virtual inheritance *unless* you are planning to inherit from the same thing in multiple ways. I would suggest just using regular public inheritance unless you actually need the virtual inheritance. Such an approach would save some poor maintenance programmer a lot of head scratching, and increase the probability that your code isn't broken by subsequent modifications. One of the great dangers of life is when a maintenance programmer decides - correctly or not - that you're full of **** and that you throw in all kinds of things you don't need; in such a case he/she will probably just go through and globally remove all the virtual inheritance, including the one or two places you really do need it. It is somewhat better to use what you need, so that anyone reading your code and finding virtual inheritance will stop and think 'hmmm, there must be a good reason for this, let me tread lightly.'
Actually, the reason I'm using this pattern is to _anticipate_ future
extensions of the interfaces, so that mixin classes will not cause a ripple of
edits to occur. It is convenient and semantically correct to inherit virtually
from all pure abstract classes intended to act as interfaces (in fact, this is
analogous to what Java does automatically with interfaces). The question is
whether it is practical "in real life".
Like I said, this technique has paid off in ease of maintenance (rule of
thumb: is it an interface? If so, inherit virtually, always), but it comes at
a (slight) runtime cost.
Is it worth it? Well, it depends on your application. What I'd like to learn
are different methods that people have used to address this problem.
As for a maintenance programmer thinking I'm full of ****, I'm sure this is
not the only technique I use that exposes me to that risk ;-). Hey, if there's
one thing I've learned, it's that it's always the _last_ guy to touch the code
who's full of **** ;-P
-dr
Dave Rahardja wrote:
On Wed, 31 Jan 2007 20:04:45 +0100, "Maarten Kronenburg"
<M.**********@inter.nl.netwrote:
>> "Dave Rahardja" wrote in message
>>Since C++ is missing the "interface" concept present in Java, I've been
using
>>the following pattern to simulate its behavior:
Dave, Just mentioning that virtual inheritance is only usefull when an abstract class is multiply inherited, that is shared, see The C++ Programming Language, Stroustrup, 3rd ed., 15.2.4.
I know that. The problem is that I may not know _when_ an abstract class
will be multiply inherited from _in the future_.
>>About the cost of virtual functions, see also: http://www.parashift.com/c++-faq-lit...functions.html In my opinion this cost may be an issue only for very small objects.
I'm not concerned about the cost of virtual functions. I'm concerned about
the cost of virtual inheritance.
Well, you were talking about an extra pointer indirection. Calling a virtual
member function on a compiler implementing the typcial vtable model
involves three already.
Dave Rahardja wrote:
On 31 Jan 2007 11:16:31 -0800, "Michael" <mc******@aol.comwrote:
>>On Jan 31, 8:46 am, Dave Rahardja <a...@me.comwrote:
>>Since C++ is missing the "interface" concept present in Java, I've been using the following pattern to simulate its behavior:
class Interface0 { public: virtual void fn0() = 0;
};
class Interface1 { public: virtual void fn1() = 0;
};
class Implementation0: public virtual Interface0, // note "public virtual" public virtual Interface1 { public: virtual void fn0(); // implementation virtual void fn1(); // implementation /* ... */
};
Two points: 1) It is typically a good idea to declare a virtual destructor in any class you're planning on inheriting from. This would include your interfaces.
Only if you plan on destroying objects through those interfaces. But point
taken.
If you have virtual member functions, it's usually a good idea to also spend
the class a virtual destructor, too.
Maybe interfaces should have the following format by default:
class Interface
{
public:
virtual void fn() = 0; // etc
private:
~Interface();
};
...which will prevent destruction through the interface.
Actually this will make it unusable, because you can't derive from it
anymore. The destructor should be protected instead of private.
Btw: Why exactly do you want to prevent destroying the object through the
interface?
On Wed, 31 Jan 2007 22:02:19 +0100, Rolf Magnus <ra******@t-online.dewrote:
>Maybe interfaces should have the following format by default:
class Interface { public: virtual void fn() = 0; // etc
private: ~Interface(); };
...which will prevent destruction through the interface.
Actually this will make it unusable, because you can't derive from it anymore. The destructor should be protected instead of private. Btw: Why exactly do you want to prevent destroying the object through the interface?
Doh, maybe that should be protected.
Because sometimes it doesn't make any sense to destroy certain objects through
particular interfaces.
But like I said, point taken.
-dr
"Dave Rahardja" wrote
>
I know that. The problem is that I may not know _when_ an abstract class
will
be multiply inherited from _in the future_.
I'm not concerned about the cost of virtual functions. I'm concerned about
the
cost of virtual inheritance.
Yes, and so has Marshall Cline on: http://www.parashift.com/c++-faq-lit...functions.html
Having said that I never used this, if I read 15.4.2 correctly, virtual
inheritance doesn't change the vtable mechanism at all. It just changes the
number of base class objects. If that is true, the base class itself is not
affected at all, as long as you made the right member functions virtual
(including the destructor). The runtime cost of virtual inheritance is then
negative: you win runtime, because fewer base class objects have to be
constructed.
Please correct me if I'm wrong.
Regards, Maarten.
Maarten Kronenburg wrote:
The runtime cost of virtual inheritance is then
negative: you win runtime, because fewer base class objects have to be
constructed.
Fewer than what?
Assuming that the answer is non-virtual inheritance, that's a different
class hierarchy, suitable for a different set of problems. So comparing
runtime code isn't really appropriate, because they do two different things.
--
-- Pete
Roundhouse Consulting, Ltd. ( www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." ( www.petebecker.com/tr1book)
On Thu, 1 Feb 2007 00:00:41 +0100, "Maarten Kronenburg"
<M.**********@inter.nl.netwrote:
> "Dave Rahardja" wrote
>> I know that. The problem is that I may not know _when_ an abstract class
will
>be multiply inherited from _in the future_. I'm not concerned about the cost of virtual functions. I'm concerned about
the
>cost of virtual inheritance.
Yes, and so has Marshall Cline on: http://www.parashift.com/c++-faq-lit...functions.html
That part of the FAQ specifically ignores virtual inheritance and RTTI. As
mentioned many times in the page:
| Note: the above discussion is simplified considerably, since it doesn't
| account for extra structural things like multiple inheritance, virtual
| inheritance, RTTI, etc., nor does it account for space/speed issues such
| as page faults, calling a function via a pointer-to-function, etc.
>Having said that I never used this, if I read 15.4.2 correctly, virtual inheritance doesn't change the vtable mechanism at all. It just changes the number of base class objects. If that is true, the base class itself is not affected at all, as long as you made the right member functions virtual (including the destructor). The runtime cost of virtual inheritance is then negative: you win runtime, because fewer base class objects have to be constructed. Please correct me if I'm wrong. Regards, Maarten.
Using virtual inheritance absolutely _does_ change the vtable mechanism: it
adds an extra indirection. Let's take the following example:
class A { /* pure virtual functions */ };
class B {};
class C : public virtual A { /* complete implementation of A */ };
class D: public B, public C {};
The data structure for class C may be represented as:
+-------------------+ -.
| Ptr to A vtable | +- A part
+-------------------+ -'
| Ptr to A part | |
| - - - - - - - - - | +- C part
| C data | |
+-------------------+ -
While the data structure for class D may be represented as:
+-------------------+ -.
| Ptr to A vtable | +- A part
+-------------------+ -'
| B data | +- B part
+-------------------+ -'
| Ptr to A part | |
| - - - - - - - - - | +- C part
| C data | |
+-------------------+ -.
| D data | +- D part
+-------------------+ -'
Notice that the position of the A part relative to the C part has moved,
depending on which object is instantiated. If you had a function that must
deal with C pointers that internally upcasts the pointer to an A pointer:
void fn(C* cptr)
{
A* aptr = cptr;
/* ... */
}
int main()
{
C c;
D d;
fn(&c);
fn(&d);
}
How would the function's code know how to find the A part of the object,
having only a pointer to C? It can't, unless C contains a pointer to the A
part of the object. Therefore, calls to virtual functions defined in class A
must undergo one additional indirection to find the correct vtable, for a
total of four indirections, analogous to:
ptr_to_object->ptr_to_a_part->ptr_to_a_vtable[virtual_fn_index]();
-dr
"Dave Rahardja" wrote
On Thu, 1 Feb 2007 00:00:41 +0100, "Maarten Kronenburg"
<M.**********@inter.nl.netwrote:
"Dave Rahardja" wrote
Using virtual inheritance absolutely _does_ change the vtable mechanism:
it
adds an extra indirection. Let's take the following example:
class A { /* pure virtual functions */ };
class B {};
class C : public virtual A { /* complete implementation of A */ };
class D: public B, public C {};
The data structure for class C may be represented as:
+-------------------+ -.
| Ptr to A vtable | +- A part
+-------------------+ -'
| Ptr to A part | |
| - - - - - - - - - | +- C part
| C data | |
+-------------------+ -
In my opinion the C object only consists of an A part, a C part and one
pointer to the C vtable. There is no Ptr to A part, only an A part. Every
object of base class A or a class derived from it only gets one pointer to
the vtable of that class. Therefore always only one vtable indirection takes
place, no matter how many times it is derived. See also More Effective C++,
Scott Meyers, item 24.
The virtual in virtual inheritance in your example could also be omitted. It
only makes a change if the base class is multiply inherited by some derived
class. See also 10.1 in the standard N2143.
It would make a change if you had:
class B : public virtual A {...}
because then class D would have inherited A two times, and the virtual
inheritance would make having one A part in D, instead of two.
This is of course if I understand the book and the standard correctly.
Hope this helps,
Regards, Maarten.
"Pete Becker" wrote
Maarten Kronenburg wrote:
The runtime cost of virtual inheritance is then
negative: you win runtime, because fewer base class objects have to be
constructed.
Fewer than what?
Assuming that the answer is non-virtual inheritance, that's a different
class hierarchy, suitable for a different set of problems. So comparing
runtime code isn't really appropriate, because they do two different
things.
>
If they would not do two different things, comparing runtime would be rather
pointless.
On Thu, 1 Feb 2007 03:11:48 +0100, "Maarten Kronenburg"
<M.**********@inter.nl.netwrote:
> "Dave Rahardja" wrote
>On Thu, 1 Feb 2007 00:00:41 +0100, "Maarten Kronenburg" <M.**********@inter.nl.netwrote:
> "Dave Rahardja" wrote
Using virtual inheritance absolutely _does_ change the vtable mechanism:
it
>adds an extra indirection. Let's take the following example:
class A { /* pure virtual functions */ }; class B {}; class C : public virtual A { /* complete implementation of A */ }; class D: public B, public C {};
The data structure for class C may be represented as:
+-------------------+ -. | Ptr to A vtable | +- A part +-------------------+ -' | Ptr to A part | | | - - - - - - - - - | +- C part | C data | | +-------------------+ -
In my opinion the C object only consists of an A part, a C part and one pointer to the C vtable. There is no Ptr to A part, only an A part. Every object of base class A or a class derived from it only gets one pointer to the vtable of that class. Therefore always only one vtable indirection takes place, no matter how many times it is derived. See also More Effective C++, Scott Meyers, item 24. The virtual in virtual inheritance in your example could also be omitted. It only makes a change if the base class is multiply inherited by some derived class. See also 10.1 in the standard N2143. It would make a change if you had: class B : public virtual A {...} because then class D would have inherited A two times, and the virtual inheritance would make having one A part in D, instead of two. This is of course if I understand the book and the standard correctly. Hope this helps, Regards, Maarten.
I'm afraid you've missed the point of my example. The fact that D has only one
copy of A is immaterial--what I was trying to show was that the "relative
distance" of a base class (A) and a class that virtually inherits from it (C)
can vary depending on the concrete class.
A function such as fn() in my previous example would have no way to determine
where the A vtable (or A's data for that matter) given a C pointer. Thus the
necessity of an additional pointer to a virtual base class.
-dr
Maarten Kronenburg wrote:
"Pete Becker" wrote
>Maarten Kronenburg wrote:
>>The runtime cost of virtual inheritance is then negative: you win runtime, because fewer base class objects have to be constructed.
Fewer than what?
Assuming that the answer is non-virtual inheritance, that's a different class hierarchy, suitable for a different set of problems. So comparing runtime code isn't really appropriate, because they do two different
things.
If they would not do two different things, comparing runtime would be rather
pointless.
No, different ways of implementing the same thing may have different
size and speed implications. But that's not the situation here: having
multiple bases of the same type is not the same as having a single
virtual base of that type. There are times when you want one and times
when you want the other. (and getting a complaint from the compiler
about ambituity is not, in itself, a reason to change to a virtual base).
--
-- Pete
Roundhouse Consulting, Ltd. ( www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." ( www.petebecker.com/tr1book)
"Dave Rahardja" wrote
I'm afraid you've missed the point of my example. The fact that D has only
one
copy of A is immaterial--what I was trying to show was that the "relative
distance" of a base class (A) and a class that virtually inherits from it
(C)
can vary depending on the concrete class.
A function such as fn() in my previous example would have no way to
determine
where the A vtable (or A's data for that matter) given a C pointer. Thus
the
necessity of an additional pointer to a virtual base class.
Yes, I now understand that virtual inheritance (and any multiple
inheritance) may also generate a "pointer" in the object, but this
inheritance pointer is more an offset for determining where the data members
are, and totally different from the vtable pointer. This also happens if
there are no virtual functions at all. Every object only needs one vtable
pointer to the vtable of its class (that is the runtime type). A virtual
function may call the base class version of that virtual function, like:
class A
{ virtual void f1()
{ ... };
};
class B : public A
{ void f1()
{ A::f1();
...
};
};
But this calling A::f1() is resolved at compile time, and not at runtime, so
the vtable of A is never needed in a B object. Which virtual function is
called only depends on the runtime type of the object (that is to which
vtable its vtable pointer points), and not on the type of some pointer
pointing to the object itself.
The type of the pointer pointing to the object is only used at compile time
(static binding), and never for the runtime type (dynamic binding).
So we have:
1. the type of the pointer pointing to the object (compile-time type, static
binding)
2. the vtable that the vtable pointer is pointing to (run-time type, dynamic
binding)
3. the offset to the base class data in multiple or virtual inheritance
Now the point is that in my understanding these three things should be
considered totally independent. In particular, calling a virtual function
only involves 2, and never 3, and therefore requires always only one vtable
indirection, and nothing more. It seems that 3 is only involved in
determining where the data members of the different classes should be found.
But agreed that the multiple or virtual inheritance offset pointer may also
cost runtime. But using virtual inheritance only seems to be usefull when
the number of base class objects can be reduced, as mentioned in the
examples. But if it is only used with one base class derivation, as in your
example, then it seems to me that it only generates extra overhead for
finding the base class member data, but not for the vtable indirection.
But I agree that reading Item 24 in More Effective C++ suggests that an
object could contain more than one vtable pointer, but I don't see any
reason for that, because an object can only have one runtime type, and
explicitly calling another version of the virtual function is resolved at
compile time, as mentioned above.
Now what about downcasting with dynamic_cast? As far as I understand it, a
dynamic_cast does not change the runtime type of an object, it only checks
the runtime type to see if the dynamic_cast can return a legal pointer (that
is if the type casted to is the runtime type or some base class type of it).
So even from this new dynamic_casted pointer, the runtime type remains
identical, and still no other vtable pointers than the one of the runtime
type are needed.
Regards, Maarten.
Maarten Kronenburg wrote:
>
"Dave Rahardja" wrote
>I'm afraid you've missed the point of my example. The fact that D has only
one
>copy of A is immaterial--what I was trying to show was that the "relative distance" of a base class (A) and a class that virtually inherits from it
(C)
>can vary depending on the concrete class.
A function such as fn() in my previous example would have no way to
determine
>where the A vtable (or A's data for that matter) given a C pointer. Thus
the
>necessity of an additional pointer to a virtual base class.
Yes, I now understand that virtual inheritance (and any multiple
inheritance) may also generate a "pointer" in the object, but this
inheritance pointer is more an offset for determining where the data
members are, and totally different from the vtable pointer. This also
happens if there are no virtual functions at all. Every object only needs
one vtable pointer to the vtable of its class (that is the runtime type).
A virtual function may call the base class version of that virtual
function, like: class A
{ virtual void f1()
{ ... };
};
class B : public A
{ void f1()
{ A::f1();
...
};
};
But this calling A::f1() is resolved at compile time, and not at runtime,
so the vtable of A is never needed in a B object. Which virtual function
is called only depends on the runtime type of the object (that is to which
vtable its vtable pointer points), and not on the type of some pointer
pointing to the object itself.
The type of the pointer pointing to the object is only used at compile
time (static binding), and never for the runtime type (dynamic binding).
However, it is needed for B::f1().
So we have:
1. the type of the pointer pointing to the object (compile-time type,
static binding)
2. the vtable that the vtable pointer is pointing to (run-time type,
dynamic binding)
3. the offset to the base class data in multiple or virtual inheritance
That offset can be determined at compile time.
Now the point is that in my understanding these three things should be
considered totally independent. In particular, calling a virtual function
only involves 2, and never 3, and therefore requires always only one
vtable indirection, and nothing more.
However, that usually resolves to three levels of pointer indirections.
But I agree that reading Item 24 in More Effective C++ suggests that an
object could contain more than one vtable pointer, but I don't see any
reason for that, because an object can only have one runtime type, and
explicitly calling another version of the virtual function is resolved at
compile time, as mentioned above.
Have a look at http://www.cse.wustl.edu/~mdeters/se...ll2005/mi.html
It explains how vtables are handled by GCCs C++ front end, especially for
multiple and virtual inheritance. That should explain it.
Now what about downcasting with dynamic_cast? As far as I understand it, a
dynamic_cast does not change the runtime type of an object, it only checks
the runtime type to see if the dynamic_cast can return a legal pointer
(that is if the type casted to is the runtime type or some base class type
of it). So even from this new dynamic_casted pointer, the runtime type
remains identical, and still no other vtable pointers than the one of the
runtime type are needed.
The dynamic_cast doesn't have to return the same address your provided. It
might add an offset.
"Rolf Magnus" wrote in message
Maarten Kronenburg wrote:
The type of the pointer pointing to the object is only used at compile
time (static binding), and never for the runtime type (dynamic binding).
However, it is needed for B::f1().
Yes, but the runtime type version (via vtable) is only called when calling
it like x.f1() or p->f1(). But calling x.B::f1() or p->B::f1() I think means
calling the class B version, no matter what the runtime type of the object
(see [class.virtual]).
>
So we have:
1. the type of the pointer pointing to the object (compile-time type,
static binding)
2. the vtable that the vtable pointer is pointing to (run-time type,
dynamic binding)
3. the offset to the base class data in multiple or virtual inheritance
That offset can be determined at compile time.
Yes that seems me to be correct. The data members are never virtual in the
virtual function sense.
>
Now the point is that in my understanding these three things should be
considered totally independent. In particular, calling a virtual
function
only involves 2, and never 3, and therefore requires always only one
vtable indirection, and nothing more.
However, that usually resolves to three levels of pointer indirections.
When I read: http://www.parashift.com/c++-faq-lit....html#faq-20.4
then I think it is a little less, more like 2 extra indirections
(fetch,fetch,call).
>
But I agree that reading Item 24 in More Effective C++ suggests that an
object could contain more than one vtable pointer, but I don't see any
reason for that, because an object can only have one runtime type, and
explicitly calling another version of the virtual function is resolved
at
compile time, as mentioned above.
Have a look at http://www.cse.wustl.edu/~mdeters/se...ll2005/mi.html
It seems to me that when using two vtable pointers in one object, then the
runtime type of the object can change. As mentioned this is also more or
less suggested by Item 24 in More Effective C++, the picture on page 120.
But in the standard in [class.virtual] item 7: "The interpretation of the
call of a virtual function depends on the type of the object for which it is
called (the dynamic type), whereas...". In my opinion, when using two vtable
pointers in one object, the dynamic type is no longer unique for an object,
but can change, which I think is not mentioned in the standard.
If I say:
Base *p = new Derived3();
no matter how many times the object is (multiply) derived, I expect that
object to remain of the same run-time type (Derived3) during its lifetime.
The compile-time type of the pointer can of course be changed with casts,
but as mentioned this should as far as I know not change the vtable pointer,
that is the run-time type. This is why I think that an object can have only
one vtable pointer.
>
It explains how vtables are handled by GCCs C++ front end, especially for
multiple and virtual inheritance. That should explain it.
Now what about downcasting with dynamic_cast? As far as I understand it,
a
dynamic_cast does not change the runtime type of an object, it only
checks
the runtime type to see if the dynamic_cast can return a legal pointer
(that is if the type casted to is the runtime type or some base class
type
of it). So even from this new dynamic_casted pointer, the runtime type
remains identical, and still no other vtable pointers than the one of
the
runtime type are needed.
The dynamic_cast doesn't have to return the same address your provided. It
might add an offset.
See my comment above.
Regards, Maarten.
Dave Rahardja wrote:
>
Since C++ is missing the "interface" concept present in Java, I've been
using
the following pattern to simulate its behavior:
Abstract class is what you need. C++ is compiling language, so you must
create object by any, but defined way. If you write "class Implementation
implement Itf0" how object of Implementation should be created?
>
class Interface0
{
public:
virtual void fn0() = 0;
make virtual dtor
virtual ~Interface0(){}
};
class Interface1
{
public:
virtual void fn1() = 0;
make virtual dtor
virtual ~Interface1(){}
};
class Implementation0: public virtual Interface0, // note "public virtual"
public virtual Interface1
You can refuse from virtual base classes. Write like this
class Implementation0: public Interface0,
public Interface1
{
public:
virtual void fn0(); // implementation
you no need to repeat virtual here
{
public:
void fn0(); // implementation
void fn1(); // implementation
/* ... */
make virtual dtor
virtual ~Implementation0(){}
};
Using virtual inheritance also allows me to create mixin classes. For
example:
class DefaultInterface0Implementation : public virtual Interface0
Here the same - avoid virtual base
class DefaultInterface0Implementation : public Interface0
{
public:
virtual void fn0(); // implementation
You no need to repeat virtual here
{
public:
void fn0(); // implementation
};
>
class Implementation1: public virtual Interface0,
public virtual Interface1,
private DefaultInterface0Implementation // mixin
{
You are trying to inherit implementation here: "private
DefaultInterface0Implementation". In most cases is better to do composition
instead
template<class Imp=DefaultInterface0Implementation>
class Implementation1: public Interface0,
public Interface1
{
protected:
Imp imp;
public:
void fn0(){imp->fn0();}
void fn1(){imp->fn1();}
public:
virtual ~Implementation0(){}
};
Does anyone have a better set of rules that I can consider using?
Try learn "desing patterns" if you have learnt about non-OO programming,
abstract data types and three bases of OOP (polimorphism, inheritance,
encapsulation) and its goals.
--
Maksim A. Polyanin
"In thi world of fairy tales rolls are liked olso"
/Gnume/
On Tue, 6 Feb 2007 21:48:24 +0300, "Grizlyk" <gr******@yandex.ruwrote:
>Try learn "desing patterns" if you have learnt about non-OO programming, abstract data types and three bases of OOP (polimorphism, inheritance, encapsulation) and its goals.
Please read the previous posts in this thread before adding your comments.
Explanations on why I chose to use virtual inheritance, etc. are present in
the original posts.
-dr
Dave Rahardja wrote:
>
>>Try learn "desing patterns" if you have learnt about non-OO programming, abstract data types and three bases of OOP (polimorphism, inheritance, encapsulation) and its goals.
Please read the previous posts in this thread before adding your comments.
Explanations on why I chose to use virtual inheritance, etc. are present
in
the original posts.
I have read it but do not find any objections to my advice. If you want to
increase the quality of your classes and apply to your programm OO design,
you must not to see on classes from coding side.
"Desing patterns" can help you to build classes and you will see, why
inheritance of implementation from your example is not a best decision in
the case. And in oder to understand design pattern you need to understand
more simple things, as I enumerated.
Once day I already have written about it, serach group
>For 5, they say, there is "easy to understand" book: A. Shalloway, J. Trott Design Pattern Explained Addison-Wesley, 2002 www.netobjectives.com/dpexplained
And what about example of composition? Why not?
You are trying to inherit implementation here: "private
DefaultInterface0Implementation". In most cases is better
to do composition instead
template<class Imp=DefaultInterface0Implementation>
class Implementation1: public Interface0,
public Interface1
{
protected:
Imp imp;
public:
void fn0(){imp->fn0();}
void fn1(){imp->fn1();}
public:
virtual ~Implementation0(){}
};
This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: qazmlp |
last post by:
class base
{
// other members
public:
virtual ~base()
{
}
virtual void virtualMethod1()=0 ;
virtual void virtualMethod2()=0 ;
virtual void...
|
by: christopher diggins |
last post by:
Since nobody responded to my earlier post , I thought I
would try to explain what I am doing a bit differently.
When multiply inheriting pure...
|
by: Matthew Louden |
last post by:
I want to know why C# doesnt support multiple inheritance? But why we can
inherit multiple interfaces instead? I know this is the rule, but I dont...
|
by: Just D |
last post by:
All,
What are advantages and disadvantages of these two different approaches?
1 . I create a base class with a few virtual methods, then I...
|
by: Bruno van Dooren |
last post by:
Hi all,
i am having a problems with inheritance.
consider the following:
class A
{
public:
A(int i){;}
};
|
by: Imre |
last post by:
Hi!
I've got some questions regarding heavy use of virtual inheritance.
First, let's see a theoretical situation, where I might feel tempted to...
|
by: mijobee |
last post by:
I'm very new to c++ and just writing some code to learn. I've run into
a problem, with a javaish design, and want to know if there is any
possible...
|
by: Kemmylinns12 |
last post by:
Blockchain technology has emerged as a transformative force in the business world, offering unprecedented opportunities for innovation and...
|
by: jalbright99669 |
last post by:
Am having a bit of a time with URL Rewrite. I need to incorporate http to https redirect with a reverse proxy. I have the URL Rewrite rules made...
|
by: antdb |
last post by:
Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine
In the overall architecture, a new "hyper-convergence" concept was...
|
by: Matthew3360 |
last post by:
Hi there. I have been struggling to find out how to use a variable as my location in my header redirect function.
Here is my code.
...
|
by: Matthew3360 |
last post by:
Hi, I have a python app that i want to be able to get variables from a php page on my webserver. My python app is on my computer. How would I make it...
|
by: AndyPSV |
last post by:
HOW CAN I CREATE AN AI with an .executable file that would suck all files in the folder and on my computerHOW CAN I CREATE AN AI with an .executable...
|
by: Arjunsri |
last post by:
I have a Redshift database that I need to use as an import data source. I have configured the DSN connection using the server, port, database, and...
|
by: Matthew3360 |
last post by:
Hi,
I have been trying to connect to a local host using php curl. But I am finding it hard to do this. I am doing the curl get request from my web...
|
by: Rahul1995seven |
last post by:
Introduction:
In the realm of programming languages, Python has emerged as a powerhouse. With its simplicity, versatility, and robustness, Python...
| |