2011-01-22 19 views
6

questa è una specie di domanda sui compiti. Per il codice seguente,come determinare sizeof class con funzioni virtuali?

#include <iostream> 
using namespace std; 

class A 
{ 
public: 
    virtual void f(){} 
}; 

class B 
{ 
public: 
    virtual void f2(){} 
}; 

class C: public A, public B 
{ 
public: 
    virtual void f3(){} 
}; 

class D: public C 
{ 
public: 
    virtual void f4(){} 
}; 

int main() 
{ 
    cout<<sizeof(D)<<endl; 
} 

L'output è: 8

Qualcuno potrebbe spiegare come è di 8 byte? Se l'implementazione di vtable dipende dal compilatore, che cosa dovrei rispondere per questo tipo di domande nelle interviste? Che dire delle classi base virtuali?

EDIT: sto lavorando su una piattaforma a 32 bit.

+1

L'operatore 'sizeof' non è veramente significativo per i tipi di classe nella maggior parte degli scenari. Se stai facendo affidamento sulle dimensioni di una classe per qualcosa, le probabilità sono buone (anche se non al 100%) che il tuo progetto sia andato male da qualche parte. Puoi approfondire ciò che stai cercando di realizzare nei tuoi compiti, o è questa la vera domanda dei compiti? (Se è il secondo e l'istruttore non ha specificato un particolare compilatore o piattaforma, l'unica risposta corretta è "la dimensione della classe è un dettaglio di implementazione.") –

+0

@ Jonathan: ho affrontato questa domanda in un test scritto molto tempo fa, non esisteva alcuna opzione del tipo "dipendente dall'implementazione" in più scelte date. Il nome dell'azienda è Phil ***. Penso, non posso menzionare il nome della compagnia qui :) – bjskishore123

+0

Bene, allora la prova scritta non consentiva la risposta corretta. Questo non lo rende scorretto. Né "8 byte" né "due puntatori" né "64 bit" è la risposta giusta, anche se è accurata su una particolare combinazione sistema/compilatore. –

risposta

13

Questo è ovviamente dipendente dall'implementazione. E farebbe una terribile domanda di intervista. Un buon programmatore C++ può semplicemente fidarsi di sizeof per avere ragione e lasciare che il compilatore si preoccupi di quelle cose vtable.

Ma quello che sta succedendo qui è che una tipica implementazione basata su vtable ha bisogno di due vtables in oggetti della classe C o D. Ogni classe base ha bisogno del proprio vtable. I nuovi metodi virtuali aggiunti da C e D possono essere gestiti estendendo il formato vtable da una classe base, ma i vtables usati da A e B non possono essere combinati.

In pseudo-codice C, ecco come un oggetto più derivato di tipo D appare sul mio applicazione (g ++ 4.4.5 Linux x86):

void* D_vtable_part1[] = { (void*) 0, &D_typeinfo, &A::f1, &C::f3, &D::f4 }; 
void* D_vtable_part2[] = { (void*) -4, &D_typeinfo, &B::f2 }; 

struct D { 
    void** vtable_A; 
    void** vtable_B; 
}; 

D d = { D_vtable_part1 + 1, D_vtable_part2 + 1 }; 
+0

+1, ora ho una certa chiarezza. – bjskishore123

+8

È una buona domanda di intervista per la posizione di un compilatore di compilatori C++ ... –

+0

Non lo considero una terribile domanda di intervista. Mostrerà chiaramente se il candidato sa, o no, cosa sta succedendo sotto il cofano. Vorrei anche fare domande sull'hardware (processore/cache/RAM ecc.) Solo per conoscere l'estensione della conoscenza della persona che sono disposto a reclutare. Anche se potrebbe non essere necessario per le attività quotidiane, la conoscenza non viene mai sprecata. –

0

Perdonami per essere stato vago, ma stai dicendo che sono compiti a casa in natura.

Vedere che sizeof() restituisce per le altre classi. La tua risposta varierà a seconda del compilatore e se ti trovi in ​​un ambiente a 32 o 64 bit.

Felice investigazione!

+0

Per la macchina a 32 bit, esiste un modo standard per determinarlo? invece di investigare per ogni caso :) – bjskishore123

+0

Non c'è un modo standard, tuttavia è _likely_ che la tua classe C tiene due puntatori a tabelle virtuali distinte. –

-2

La dimensione dell'oggetto ha niente a che fare con quanti metodi ha, né se questi metodi sono virtuali o meno. La dimensione di un oggetto è determinata solo dalle sue variabili membro.

Non posso dirti esattamente perché stai ricevendo una dimensione di 8 byte. Dato che non ci sono membri di dati nella tua classe, un compilatore C++ potrebbe in teoria generare una classe che non occupa affatto uno spazio [1]! Sto indovinando che gli 8 byte è il minimo richiesto per fornire un puntatore al vtbl, più eventualmente un po 'di padding.

[1] Penso. Non è il momento di verificare le specifiche per sapere se

+0

@JSBangs: mentre sto lavorando su una piattaforma a 32 bit, vptr richiede 4 byte. – bjskishore123

+0

@JSBangs: 'sizeof' non restituisce mai zero, ma un subobject di classe base può occupare zero byte. – aschepler

+1

@JSBangs @ bjskishore123: la dimensione di un 'D' è di 8 byte perché contiene * due * puntatori a 32 bit vtable. Ce n'è due per il fatto che la classe 'D' deriva dalla classe' C' che deriva da due classi diverse con funzioni virtuali: classe 'A' e' B'. La presenza di funzioni virtuali richiede almeno un puntatore a un vtable nell'oggetto in quasi ogni implementazione C++. Ecco come viene implementato il polimorfismo. –

1

In questa domanda, se si tenta di ottenere classe Sizeof A, ti darà la risposta '4' perché A ha solo una funzione virtuale, quindi il suo __vptr sarà del byte '4'.

Allo stesso modo, se si tenta di ottenere Sizeof di classe B, questo darà la risposta '4' perché B ha anche una sola funzione virtuale, quindi il suo __vptr sarà di '4' byte.

Ma la classe C eredita entrambe le classi A & B e C hanno una funzione virtuale. Quindi C riceverà 2 puntatori __vptr, e per la propria funzione virtuale C userà l'__vptr ereditato. Quindi se provate ad ottenere Sizeof di classe C, vi darà la risposta '8' perché C ha due puntatori virtuali.

Infine, la classe D eredita la classe C, quindi D utilizzerà __vptr ereditato per la propria funzione virtuale e poiché la classe C ha dimensione di byte '8', quindi sizeof D ti darà il byte risposta '8'.

Problemi correlati