4

I am baffled by the VIRTUAL keyword. I am trying to find how does compiler implement this in memory. ok so let me explain with examples. I am using Microsoft Visual studio 2010 as implementation of virtual depends on compiler.

here is the first code

#include<iostream>
class one
{
    int _a;
public:
    virtual ~one(){}
};
class two:public one
{
    int _a;
public:
    virtual ~two(){}
};

int main()
{
    using namespace std;
    cout<<"sizeof two="<<sizeof(two)<<endl;
    return 0;
}

o/p is 12 bytes, because of _vptr_two,one::_a and two::_a

here is another example code

#include<iostream>
class one
{
    int _a;
public:
    virtual ~one(){}
};
class two
{
    int _a;
public:
    virtual ~two(){}
};
class three:virtual public one,virtual public two
{
};

int main()
{
    using namespace std;
    cout<<"sizeof three="<<sizeof(three)<<endl;
    return 0;
}

in this case o/p is 20 bytes :O, how come?? Please explain!! According to me it should be 16 bytes. __vptr_three(pointer to vtable), _vptr1_three(pointer to virtual base class table), one::_a and two::_a. And why virtual base class table is maintained ?

2
  • Note: your example of virtual base class is... strange. In theory virtual inheritance is used to solve the Diamond Problem: D inherits from C and B and both C and B inherit from A. You have no diamond, so virtual inheritance is useless in your case. Commented Feb 20, 2014 at 7:44
  • @MatthieuM. your point is relevant matt but i am not trying to implement anything i am just learning :) and when you learn you should learn all aspects !!! Commented Feb 20, 2014 at 8:44

2 Answers 2

8

This pdf contains everything that you need to understand about, how virtual inheritance is implemented in VC++, by the writer of the compiler.

Below is the disassembly for the constructor of class three,

00A516BD  cmp         dword ptr [ebp+8],0 
00A516C1  je          three::three+60h (0A516F0h) 
00A516C3  mov         eax,dword ptr [this] 
00A516C6  mov         dword ptr [eax],offset three::`vbtable' (0A57828h) => 4 Bytes
00A516CC  mov         ecx,dword ptr [this] 
00A516CF  add         ecx,8 
00A516D2  call        one::one (0A51253h) 
00A516D7  or          dword ptr [ebp-0D4h],1 
00A516DE  mov         ecx,dword ptr [this] 
00A516E1  add         ecx,10h 
00A516E4  call        two::two (0A512BCh) 
00A516E9  or          dword ptr [ebp-0D4h],2 
00A516F0  mov         eax,dword ptr [this] 
00A516F3  mov         ecx,dword ptr [eax] 
00A516F5  mov         edx,dword ptr [ecx+4] 
00A516F8  mov         eax,dword ptr [this] 
00A516FB  mov         dword ptr [eax+edx],offset three::`vftable' (0A57820h)  => 4 Bytes
00A51702  mov         eax,dword ptr [this] 
00A51705  mov         ecx,dword ptr [eax] 
00A51707  mov         edx,dword ptr [ecx+8] 
00A5170A  mov         eax,dword ptr [this] 
00A5170D  mov         dword ptr [eax+edx],offset three::`vftable' (0A57814h)   => 4 Bytes
00A51714  mov         eax,dword ptr [this] 
00A51717  pop         edi  
00A51718  pop         esi  
00A51719  pop         ebx  
00A5171A  add         esp,0D8h 

As you can see above,
The virtual base table pointer takes 4 bytes, (vbtable)
2 virtual function table pointer takes 4 * 2 = 8 bytes, (vftable)
The member one::_a takes 4 bytes
The member two::_a takes 4 bytes

Hence in all 20 bytes. The reason for 2 virtual function table pointers is given in the pdf (page 17) as follows,

"In Visual C++, to avoid costly conversions to the virtual base P when fetching a vftable entry, new virtual functions of T, receive entries in a new vftable, requiring a new vfptr, introduced at the top of T."

Sign up to request clarification or add additional context in comments.

4 Comments

I think, you should add some paragraphs from the pdf to the answer in case if this pdf will be removed.
Indeed, link-only answers are frowned upon because they tend to link-rot. It is fine, and actually encouraged, to provide references to supplement your answers; however the meat of the answer should be immediately accessible on Stack Overflow (if only in broad strokes). It would also be helpful if you explained why 20...
@51k good to know that the pdf answers it,hang on i am on page 11 :) !!
"As you can see above" -- this should read "As you can clearly see above"
2

This is entirely implementation-specific, and a compiler is at liberty to organise things any way it likes (and make the resulting classes any size it likes) providing it all works.

From the look of things, I assume that class three contains three hidden pointers (each 4 bytes on your system): one "virtual base pointer", containing the addresses of the virtual bases within three, one virtual function pointer containing the addresses of the virtual functions in one, and a second virtual function pointer containing the addresses of the virtual functions in two.

So that's 3 * 4 bytes for the pointers, plus 2 * 4 bytes for the two int members of the base classes, giving a total of 20 bytes.

Of course, if you were to compile this code on a 64-bit machine (with 8 byte pointers), then you'd get something different: at least 32 bytes, but possibly more if the compiler decided it needed to pad the int members.

1 Comment

This is what i suspected too, but why two virtual function pointers ??

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.