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.