C++ vtable

Programming, for all ages and all languages.
Post Reply
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

C++ vtable

Post by Neo »

What exactly are the contents of the vtable in a C++ class with virtual functions?
I'm guessing that it needs at least 3 columns
  • 1) object type (this must be the index)
    2) function name
    3) address of function
Also how can I view the contents of the vtable? Anyone have some code that can do this?
Only Human
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re: C++ vtable

Post by Colonel Kernel »

Neo wrote:What exactly are the contents of the vtable in a C++ class with virtual functions?
I'm guessing that it needs at least 3 columns
  • 1) object type (this must be the index)
    2) function name
    3) address of function
Also how can I view the contents of the vtable? Anyone have some code that can do this?
I don't see why the object type and function name would need to be there.

Each class with at least one virtual function (or destructor) has at least one vtable. A class with more than one base class can have at most one vtable per base class. When there is more than one vtable, the right one is selected based on its offset within the object, so there is no need for the object type. I wouldn't be surprised if the vtable contained a pointer to the RTTI data for the class, but that would be a "row" in the vtable, not a "column".

The function name doesn't need to be in the vtable because in C++ functions are called by address, not by name.

You can probably write some assembler to poke around vtables. The pointer to an object's vtable is usually the first field in the object (hidden from the programmer of course). A good graphical debugger might show you a logical view of the vtable (MS Visual Studio does this). Keep in mind that vtables might look different for code compiled with different C++ compilers (and vptrs might be at different offsets in objects, etc.).
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

I haven't read that document myself yet, but it seems vtable layout is pretty well defined by the C++ ABI (provided your compiler of choice is compliant to that ABI - GCC is since some early 3.x version.)
Every good solution is obvious once you've found it.
User avatar
Kevin McGuire
Member
Member
Posts: 843
Joined: Tue Nov 09, 2004 12:00 am
Location: United States
Contact:

Post by Kevin McGuire »

I myself have started working with some C++. I have been examining assembler output to see how the internals work so I may be able to use the language more efficiently. I am sort of on a quest to determine:

Why and What I should use C++ features for.

I have been looking at the GCC optimization, and how well the syntactic sugar gets removed and replaced by equivalent code written in C. So far I have been very compelled to learn more.

So I decided to take a in depth look since I am also working with classes and wanted to know what the implications would be with using inheritance and virtual members internally.

I used Solar's post as a starting point and dived into actually viewing some memory contents using GDB. I right away noticed that as Colonel Kernel said, "The pointer to an object's vtable is usually the first field in the object (hidden from the programmer of course)." which is correct.

Code: Select all

class myClass1{public: unsigned int m; myClass1(); ~myClass1();};
class myClass2{public: unsigned int m; myClass2(); ~myClass2();
                        void virtual vFunction(void){}
                       };
class myClass3{public: unsigned int m2; myClass2(); ~myClass2();
                        void vFunction(void){}
                       };
int main(int argc, char *argv[]){
  myClass1 a;
  myClass3 c;
  unsigned int *ptr = (unsigned int*)&c;
  printf("vtable:%x\n", ptr[0]);
  printf("myClass1Size:%x\n", sizeof(myClass1));
  printf("myClass2Size:%x\n", sizeof(myClass1));
  printf("myClass3Size:%x\n", sizeof(myClass1));
printf("
When a class has no virtual members and is not inherited from it will contain no virtual table and act just like a struct apparently. However if a class inherits from it a vtable will be created. You can determine this also by the size of Class2 and Class3 being eight bytes instead of four where the hidden field has bulked it up slightly.

I also noticed as the document Solar posted which clued to the virtual functions in the vtable being order as they are declared being correct, and also that each entry in the vtable is a absolute address.

A interesting little bit was that the constructors for a class are called backwards beginning with the base class, and it is the constructor which writes the address for the vtable in the hidden member field. Each return from a inherited constructor to a caller results in this vtable address being replaced over and over again.

For myClass3:

myClass2(){ hiddenField = myClass2VTable; }
myClass3(){ myClass2(); hiddenField = myClass3VTable; }


So all in all for whom ever might be interested it appears the vtable simply follows the object instance around as a array stored separately from the class instance data in memory.


unsigned int *vtable = (unsigned int*)(&theClassInstance)[0];
vtable[0] = first_virtual_function_in_theClass_declaration;
vtable[1] = second_virtual......


The vtables so far are constructed at link time, and stored in the .rodata section of the ELF32 when using GCC(g++).

I know nothing about the RTTI, but I assume by getting clues from the document Solar posted that it could be located at the end of the vtable.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post by Candy »

Kevin McGuire wrote:A interesting little bit was that the constructors for a class are called backwards beginning with the base class, and it is the constructor which writes the address for the vtable in the hidden member field. Each return from a inherited constructor to a caller results in this vtable address being replaced over and over again.
That also leads to the behaviour you'll probably see when you call a virtual function in a base class constructor - it isn't there yet.
I know nothing about the RTTI, but I assume by getting clues from the document Solar posted that it could be located at the end of the vtable.
What would RTTI be other than a number indicating its true type? What about putting it in the vtable itself? If so, then you can just use the vtable pointer for the same purpose; I expect that this is done.
Post Reply