This is a follow-up question to this one.
Consider this example:
#include <iostream>
class A
{
};
class B : public A
{
public:
int i;
virtual void Func() = 0;
};
class C : public B
{
public:
char c;
void Func() {}
};
int main()
{
C* pC = new C;
A* pA = (A*)pC;
std::cout << "pC == " << std::hex << pC << "\n";
std::cout << "pA == " << std::hex << pA << "\n";
return 0;
}
With Visual Studio 2010, the output is (on my machine):
pC == 002DEF90 pA == 002DEF94
(this is explained by the accepted answer of the question).
With g++, the output is:
pC == 0x96c8008 pA == 0x96c8008
So, the question is, how does the implementation of g++ handle this case? What makes the addresses the same when C
should have a vtable? (I know that this is an implementation detail, don't say that :) I'm interested in this implementation detail out of curiosity).
After much fiddling, I finally remembered something.
The Empty Base Optimization.
As soon as A
gets a member, the result change. However as long as it has none, the compiler is not required to generate a real layout for A
, all that matters is to guarantee that each A
"object" will have a different address from any other A
object.
Therefore, the compiler simply use the address of the B
subobject (which inherits from A
) as a suitable address. And it turns out that B
and C
have the same address (first base + both having virtual methods).
On the other hand, if A
has a member OR if the first member of B
is a A
(there are other conditions), then the EBO cannot apply any longer and you'll notice a jump in the addresses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With