2009-12-15 4 views

Répondre

30

Dépend du compilateur.

Dans VC++, le pointeur vtable stocké au début de l'allocation d'objet, avant toute donnée de membre. (À condition que votre classe comporte au moins une fonction de membre virtuel.)

Il peut également y avoir plusieurs pointeurs vtable, si votre classe multiplie-hérite d'autres classes avec vtables.

Les vtables eux-mêmes sont alloués de manière statique quelque part dans votre espace d'adressage.

Ensuite, la mise en page de l'objet ressemble (pour une instance de C):

A's VTable ptr 
A's member variables. 
B's Vtable ptr 
B's member variables. 
C's member variables. 

pour le heirarchy

class A { 
    virtual Ax() {} 
    int a, b; 
}; 
class B { 
    virtual Bx() {} 
    int c, d; 
}; 
class C : public A, public B { 
    int foo, bar; 
}; 
+16

Je pense que vous parlez de vptr, c'est-à-dire des pointeurs vers vtables. Vtables eux-mêmes sont généralement stockés dans le segment de données statique, car ils sont spécifiques à la classe (par rapport à l'objet). –

+2

En effet, j'ai modifié mon post :) –

+1

La mise en page d'objet est pour une instance de C, non? (Par opposition à A, B et C) – Niklas

1

Le VPTR généralement au début de l'objet (Imperfect C++, Backyard Hotrodding C++) mais cela n'est pas garanti dans le standard ré. L'utilisation de vptrs et de vtables n'est pas garantie dans la norme. Si vous avez vraiment besoin de savoir où il se trouve, il est courant d'utiliser COM, XPCOM, UNO, etc. pour implémenter un endroit où quelque chose comme un vptr est situé Utilise les.

+0

Les liaisons CM ++ et CORBA C++ que j'ai utilisées laissent le placement de la vtable au compilateur C++. –

+0

Merci, j'ai supprimé CORBA de la liste –

16

Vtable? Quel vtable? Le standard C++ ne mentionne pas de vtable. Chaque compilateur peut implémenter des fonctions virtuelles comme bon lui semble. Et cela inclut placer le vtable n'importe où il aime.

+0

Je crois que le vtable peut être n'importe où sauf à l'adresse de départ de l'objet. Ma compréhension est que l'adresse du premier élément est aussi l'adresse de départ de la structure. –

+3

Non, ce n'est pas une exigence. C'est le cas pour les types POD, mais les types POD n'ont pas de vtable, donc c'est un non-problème là. Pour les types non-POD, il n'y a aucune garantie que l'adresse de la structure est la même que l'adresse du premier élément. – jalf

-1

Chaque instance qui inclut une fonction virtuelle a un pointeur de fonction virtuelle qui pointe vers la table de fonction virtuelle (vbtl), nous avons seulement pu localiser le vtbl à travers l'instance. ou vous pouvez utiliser l'objdump pour lire le symbole du fichier ELF, peut-être que vous pouvez trouver la réponse. J'espère que l'exemple suivant peut vous aider.

#include <iostream> 
#include <stdio.h> 
typedef void (*fun_pointer)(void); 

using namespace std; 
class Test 
{ 
public: 
    Test() 
    { 
    cout<<"Test()."<<endl; 
    } 
    virtual void print() 
    { 
    cout<<"Test::Virtual void print()."<<endl; 
    } 
    virtual void print2() 
    { 
    cout<<"Test::virtual void print2()."<<endl; 
    } 
}; 

class TestDrived:public Test 
{ 
public: 
    TestDrived() 
    { 
    cout<<"TestDrived()."<<endl; 
    } 
    virtual void print() 
    { 
    cout<<"TestDrived::virtual void print()."<<endl; 
    } 
    virtual void print2() 
    { 
    cout<<"TestDrived::virtual void print2()."<<endl; 
    } 
    void GetVtblAddress() 
    { 
     cout<<"vtbl address:"<<(int*)this<<endl; 
    } 
    void GetFirstVtblFunctionAddress() 
    { 
    cout<<"First vbtl function address:"<<(int*)*(int*)this+0 << endl; 
    } 
    void GetSecondVtblFunctionAddress() 
    { 
    cout<<"Second vbtl function address:"<<(int*)*(int*)this+1 << endl; 
    } 
    void CallFirstVtblFunction() 
    { 
    fun = (fun_pointer)* ((int*) *(int*)this+0); 
    cout<<"CallFirstVbtlFunction:"<<endl; 
    fun(); 
    } 
    void CallSecondVtblFunction() 
    { 
    fun = (fun_pointer)* ((int*) *(int*)this+1); 
    cout<<"CallSecondVbtlFunction:"<<endl; 
    fun(); 
    } 
private: 
    fun_pointer fun; 
}; 



int main() 
{ 
cout<<"sizeof(int):"<<sizeof(int)<<"sizeof(int*)"<<sizeof(int*)<<endl; 
fun_pointer fun = NULL; 
TestDrived a; 
a.GetVtblAddress(); 
a.GetFirstVtblFunctionAddress(); 
a.GetSecondVtblFunctionAddress(); 
a.CallFirstVtblFunction(); 
a.CallSecondVtblFunction(); 
return 0; 
} 
-2

VPTR et Vtable sont stockés dans le segment des données ...

Vtable est comme un tableau de pointeur de fonction.

Vtable et Vptr créent au moment de la compilation ce qui obtiendra de la mémoire à l'exécution et les entrées vtable sont des adresses de fonctions virtuelles.

Chaque objet d'une classe contenant une fonction virtuelle aura un pointeur supplémentaire qui pointe vers Virtual Table est appelé pointeur virtuel.

Chaque fois que nous appelons une fonction virtuelle en utilisant un objet, d'abord le Vptr corrospondant lira la fonction de Vtable au moment de l'exécution et finalement la fonction sera appelée.