Size of polymorphic class derived virtually
Asked Answered
L

2

7

I am having hard time to undertsand what constitutes the size of following classes?
I am using MSVS 2008 (VC 9.0 compiler). I have read that if I do not declare virtual functions(in below example) then Class D will contain 2 extra pointer(1 from B and another from C) which will point to the shared instance of A.

But what would be the memory map of each classes in below case(having virtual functions also) ?

class A
{
public:
    int a;
    virtual void Func();
public:
    A(void);
    ~A(void);
};

class B :virtual public A
{
public:
    int b;
    virtual void Func();
public:
    B(void);
    ~B(void);
};

class C: virtual public A
{
public:
    int c;
    virtual void Func();
public:
    C(void);
    ~C(void);
};

class D : public B, public C
{
public:
    int d;
    virtual void Func();
public:
    D(void);
    ~D(void);
};




int _tmain(int argc, _TCHAR* argv[])
{
    cout << "size of Class A :" << sizeof(A) << endl;

    cout << "size of Class B :" << sizeof(B) << endl;

    cout << "size of Class C :" << sizeof(C) << endl;

    cout << "size of Class D :" << sizeof(D) << endl;

    return 0;
}

Output:
size of Class A :8
size of Class B :20
size of Class C :20
size of Class D :32

Here, how the size of B, C & D are getting calculated ?

EDIT: Following is the memory map generated by /d1reportSingleClassLayoutXXX compiler option for each class:

1>class A size(8):  
1> +---  
1> 0 | {vfptr}  
1> 4 | a  

1>class B size(20):  //Similar for C
1> +---  
1> 0 | {vbptr}  
1> 4 | b  
1> +---  
1>8 | (vtordisp for vbase A)  
1> +--- (virtual base A)  
1>12 | {vfptr}  
1>16 | a  
1> +---  

1>class D size(32):  
1> +---  
1> | +--- (base class B)  
1> 0 | | {vbptr}  
1> 4 | | b  
1> | +---  
1> | +--- (base class C)  
1> 8 | | {vbptr}  
1>12 | | c  
1> | +---  
1>16 | d  
1> +---  
1>20 | (vtordisp for vbase A)  
1> +--- (virtual base A)  
1>24 | {vfptr}  
1>28 | a    

What is vtordisp for vbase X means here ?

Leith answered 28/2, 2014 at 9:34 Comment(0)
D
1

I would say that you are on a 32-bit machine, where sizeof(int) is 4.

Speculatively:

First, the size of A:

|int a (4)|vtable pointer A (4)|

Second, the size of B and C:

|A base instance (8)|pointer to A(4)|int b/c(4)|vtable pointer B/C|

Third, the size of D:

|A base instance (8)|pointer to A(4)|int c(4)|vtable pointer B(4)|pointer to A(4)|int d(4)|vtable pointer C(4)|

Since D is not virtually inheriting from C, it can afford to reuse vtable pointer C. Again, that's just speculation. You should try to dump the memory of an object D to be sure. And I'm not sure how your machine aligns memory.

Dull answered 28/2, 2014 at 9:57 Comment(2)
Thanks Laurent. In case of B/C, can you please elaborate how 'A base Instance' is of 8 bytes? What does it contains? 4 bytes of int a + 4 bytes of A's vptr ? I doubt so...Leith
Why do you doubt so? If you convert a B*, C* or D* to a A*, it must have the same layout than a vanilla A object.Dull
A
1

As per Jonathan Caves, MSFT

It is used very rarely - but we have to add it to classes that inherit from a virtual base class and override virtual functions just in case the user does call a virtual function in the constructor or destructor.

So -- it's MSVC's (terribly underdocumented) solution to "how do you make a virtual call during object construction?".

Anyway answered 15/12, 2014 at 16:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.