[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Virtual inheritance and vtables?
From: |
Colin D Bennett |
Subject: |
Re: Virtual inheritance and vtables? |
Date: |
Fri, 19 Oct 2007 16:34:24 -0700 |
User-agent: |
Thunderbird 2.0.0.6 (X11/20070912) |
Samuli wrote:
> class A {int a;};
>
> class B : public virtual A{};
> ...
> There are no virtual functions, so I thought there would be no
> extra pointers (to vtable) needed either. But it doesn't seem to
> play out that way.
> What information does that pointer point to? Why is it neccesary?
> Can I avoid the generation of that extra pointer somehow, while still
> using virtual base classes?
There is unavoidable overhead in using virtual base classes, so only use
them when they are to right tool for the job.
The reason is that A subobjects of instances of classes derived from B
must still be shared among all inherited classes where A is a virtual base.
For example:
#include <iostream>
class A {public: int a;};
class B : public virtual A{};
class C : public virtual A{};
class D : public B, public C {};
void use_B(B& b) { b.a = 42; }
int use_C(C& c) { return c.a; }
int main()
{
D d;
use_B(d);
int value = use_C(d);
std::cout << "c.a is " << value << '\n';
std::cout << "sizeof(A)=" << sizeof(A) << '\n';
std::cout << "sizeof(B)=" << sizeof(B) << '\n';
std::cout << "sizeof(C)=" << sizeof(C) << '\n';
std::cout << "sizeof(D)=" << sizeof(D) << '\n';
}
The output on my machine is:
c.a is 42
sizeof(A)=4
sizeof(B)=8
sizeof(C)=8
sizeof(D)=12
The data member of class A has been made public so that we can directly
access it, but that doesn't affect the object layout. Access to b.a and
c.a must use indirection through a pointer so that they both end up
accessing the same memory location. Instances of class D must have
subjects of both B and C. The when a B& is passed to use_B(), it is the
address of the B subobject within the D object that is passed. Likewise,
for use_C(), the C subobject's address is passed in.
Here is g++'s generated IA-32 assembly code for the functions using a
reference to a B object and a reference to a C object:
_Z5use_BR1B: ;; void use_B(B& b)
movl 4(%esp), %eax ; get address of b -> %eax
movl (%eax), %edx ; get A subobject offset -> %edx
movl -12(%edx), %edx ;
movl $42, (%eax,%edx) ;
ret
_Z5use_CR1C: ;; int use_C(C& c)
movl 4(%esp), %edx
movl (%edx), %eax
movl -12(%eax), %eax
movl (%edx,%eax), %eax
ret
Anyway, it's an interesting issue, but that's how virtual bases work.
Regards,
Colin