2009-12-15 11 views

Respuesta

30

Depende del compilador.

En VC++, el puntero vtable almacenado al principio de la asignación de objeto, antes de cualquier información de miembro. (Siempre que su clase tenga al menos una función de miembro virtual).

También puede haber múltiples punteros vtable, si su clase se hereda de otras clases con vtables.

Los vtables en sí están asignados estáticamente en algún lugar de su espacio de direcciones.

Entonces la disposición objeto parece (para una instancia de C):

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

para la jerarquía

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

Creo que estás hablando de vptr's, es decir, punteros a vtables. Los Vtables mismos se almacenan generalmente en el segmento de datos estáticos, ya que son específicos de clase (frente a específicos de objeto). –

+2

De hecho, modifiqué mi publicación :) –

+1

El diseño del objeto es para una instancia de C, ¿verdad? (A diferencia de A, a B y C) – Niklas

1

VPTR comúnmente al inicio del objeto (Imperfecto C++, Backyard Hotrodding C++) pero eso no está garantizado en el estándar re. El uso de vptrs y vtables no está garantizado en el estándar.

Si realmente necesita saber dónde está, es común usar algo como COM, XPCOM, UNO, etc. que se implementan al crear un lugar donde se encuentra algo así como un vptr y establecer formas de usalos, usalos a ellos.

+0

Los enlaces de CM y CORBA C++ que he usado dejan la ubicación del vtable al compilador de C++. –

+0

Gracias, eliminé CORBA de la lista –

16

Vtable? ¿Qué vtable? El estándar C++ no menciona un vtable. Cada compilador puede implementar funciones virtuales de la forma que quiera. Y eso incluye colocar el vtable donde quiera.

+0

. Creo que el vtable puede estar en cualquier lugar excepto en la dirección de inicio del objeto. Según entiendo, la dirección del primer elemento es también la dirección inicial de la estructura. –

+3

No, eso no es un requisito. Es el caso para los tipos POD, pero los tipos POD no tienen un vtable, por lo que no es un problema. Para los tipos que no son POD, no hay garantía de que la dirección de la estructura sea la misma que la dirección del primer elemento. – jalf

-1

Cada instancia que incluye la función virtual tiene un puntero de función virtual que apunta a la tabla de funciones virtuales (vbtl), solo pudimos ubicar el vtbl a través de la instancia. o puede usar objdump para leer el símbolo del archivo ELF, quizás pueda encontrar la respuesta. Espero que el siguiente ejemplo pueda ayudarte.

#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 y Vtable se almacenan en el segmento de datos ...

Vtable es como un conjunto de puntero de función.

Vtable y Vptr están creando en tiempo de compilación, lo que generará memoria en tiempo de ejecución y las entradas de vtable son direcciones de funciones virtuales.

Cada objeto de una clase que contiene una función virtual tendrá un puntero adicional que apunte a la tabla virtual que se conoce como puntero virtual.

siempre que llamemos a una función virtual usando un objeto, primero el Vptr corrosponding leerá la función de Vtable en tiempo de ejecución y finalmente se llamará a la función.

Cuestiones relacionadas