Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the g++ implementation handle this situation?

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).

like image 610
Tamás Szelei Avatar asked Apr 04 '12 10:04

Tamás Szelei


1 Answers

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.

like image 168
Matthieu M. Avatar answered Oct 25 '22 16:10

Matthieu M.