Dove nella memoria è memorizzato Vtable?Dove è memorizzato in memoria vtable?
risposta
Dipende dal compilatore.
In VC++, il puntatore vtable memorizzato all'inizio dell'allocazione dell'oggetto, prima di qualsiasi dato membro. (Se la tua classe ha almeno una funzione membro virtuale.)
Ci possono anche essere più puntatori vtable, se la tua classe si moltiplica - eredita da altre classi con vtables.
Gli stessi vtables sono allocati staticamente da qualche parte nello spazio degli indirizzi.
Poi il layout dell'oggetto assomiglia (per un'istanza di C):
A's VTable ptr
A's member variables.
B's Vtable ptr
B's member variables.
C's member variables.
per la gerarchia
class A {
virtual Ax() {}
int a, b;
};
class B {
virtual Bx() {}
int c, d;
};
class C : public A, public B {
int foo, bar;
};
Il vptr comunemente all'inizio dell'oggetto (Imperfect C++, Backyard Hotrodding C++) ma ciò non è garantito nella norma d. L'uso di vptrs e vtables non è garantito nello standard.
Se davvero hai bisogno di sapere dov'è, è comune usare qualcosa come COM, XPCOM, UNO, ecc. Che sono implementati essenzialmente con un luogo fisso in cui si trova qualcosa come un vptr e impostare modi per usali.
I collegamenti CM e CORBA C++ che ho usato lasciano il posizionamento del vtable al compilatore C++. –
Grazie, ho rimosso CORBA dall'elenco –
Vtable? Che vtable? Lo standard C++ non menziona un vtable. Ogni compilatore può implementare le funzioni virtuali come preferisce. E questo include mettere il vtable ovunque voglia.
Credo che il vtable possa essere ovunque tranne che nell'indirizzo iniziale dell'oggetto. La mia comprensione è che l'indirizzo del primo elemento è anche l'indirizzo iniziale della struttura. –
No, non è un requisito. È il caso dei tipi di POD, ma i tipi di POD non hanno un vtable, quindi è un non-problema lì. Per i tipi non POD, non vi è alcuna garanzia che l'indirizzo della struttura sia lo stesso dell'indirizzo del primo elemento. – jalf
Ogni istanza che include la funzione virtuale ha un puntatore a funzione virtuale che punta alla tabella delle funzioni virtuali (vbtl), potremmo solo individuare il vtbl attraverso l'istanza. oppure puoi usare objdump per leggere il simbolo del file ELF, forse puoi trovare la risposta. Spero che il seguente esempio possa aiutarti.
#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;
}
Vptr e Vtable vengono memorizzati nel segmento dati ...
Vtable è come una serie di puntatore a funzione.
Vtable e Vptr si creano in fase di compilazione, che otterrà la memoria in fase di esecuzione e le voci vtable sono indirizzi di funzione virtuali.
Ogni oggetto di una classe contenente una funzione virtuale avrà un puntatore aggiuntivo che punta a Tabella virtuale è noto come puntatore virtuale.
ogni volta che chiamiamo una funzione virtuale usando l'oggetto, prima il Vosptr corrosivo legge la funzione da Vtable in fase di esecuzione e alla fine verrà chiamata la funzione.
Penso che tu stia parlando di vptr, cioè puntatori ai vtables. Gli stessi Vtables sono generalmente memorizzati nel segmento dei dati statici, in quanto sono specifici della classe (rispetto agli oggetti). –
Infatti, ho modificato il mio post :) –
Il layout dell'oggetto è per un'istanza di C, giusto? (Contrariamente a A, a B e a C) – Niklas