2009-09-05 13 views
10

Aggiornamento: Sostituito l'esempio del distruttore con un esempio di chiamata di metodo diretto.Ereditarietà C++/domande VTable

Ciao,

Se ho il seguente codice:

class a 
{ 
public: 
    virtual void func0(); // a has a VTable now 
    void func1(); 
}; 
class b : public a 
{ 
public: 
    void func0() { a::func0(); } 
    void func2(); 
}; 
  1. C'è un VTable in B? B non ha funzioni virtuali ma chiama a :: func0() da b :: func0()
  2. Does func1 risiede in una VTable? Non è virtuale
  3. Does func2 risiede in una VTable?
  4. Le risposte a quanto sopra saranno diverse se non ci fosse una chiamata a :: func0() in b :: func0()?

Grazie

+5

Sarebbe bello se dicessi in tali domande quale compilatore stai usando. Le tabelle virtuali sono specifiche dell'implementazione, anche se ci sono sforzi per standardizzare il loro formato. –

+2

'b :: func0' ** è ** virtuale –

risposta

19

Se si dichiarano funzioni virtuali, è necessario dichiarare anche il distruttore virtuale ;-).

  1. B ha una tabella virtuale, perché ha una funzione virtuale, cioè func0(). Se dichiari una funzione (incluso un distruttore) virtuale in una classe base, tutte le sue classi derivate avranno anche la funzione con la stessa firma virtuale. E causerà loro di avere un vtable. Inoltre, B avrebbe il vtable anche se non hai dichiarato esplicitamente func0.

  2. Le funzioni non virtuali non sono referenziate tramite vtables.

  3. Vedi VTables 2.

  4. No. classi sono costruiti basano su dichiarazioni di classe. I corpi delle funzioni di classe (per non parlare di altre funzioni) non sono presi in considerazione. Pertanto, B ha un vtable, perché la sua funzione func0() è virtuale.

C'è anche un dettaglio difficile, anche se non è l'essenza della tua domanda. Hai dichiarato la tua funzione B::func0() come inline. Nel compilatore gcc, se una funzione virtuale viene dichiarata in linea, mantiene il suo slot nella tabella virtuale, lo slot che punta a una funzione speciale emessa per quella in linea (che conta come prendendo l'indirizzo, che rende inline emesso). Ciò significa che se la funzione è in linea non influenza la quantità di slot in vtable e la sua necessità per una classe.

+0

Aggiornato. Inoltre, in pratica se una funzione è dichiarata virtuale in * qualsiasi * classe di base nella gerarchia dell'ereditarietà, allora quella funzione è virtuale anche se la classe di base diretta (1 livello superiore) non la contrassegna come virtuale? – jameszhao00

+0

Risposta notevole. Dovrebbe essere accettato. +1 da me. –

+0

@ jameszhao00: anche aggiornato la risposta. Hai capito bene: se una qualsiasi classe di base indiretta (cioè un genitore di un genitore di qualche genitore ... della classe corrente) dichiara la funzione virtuale, è virtuale anche nella classe corrente. Nota che le funzioni sovraccaricate (void f (int) rispetto a void f (double)) sono trattate come funzioni diverse. –

5
  1. Sì, perché la sua classe di base ha uno; anche il suo distruttore è virtuale (anche se non lo hai dichiarato virtuale) perché il distruttore della classe base è virtuale.

  2. No

  3. No.

  4. No. In realtà non credo che il codice attuale è legale: il compilatore richiamerà il distruttore dopo che invoca il distruttore B, anche se don' t chiamare esplicitamente ~ A da ~ B; quindi non penso che dovresti invocare ~ A da ~ B anche se il compilatore ti permette di farlo.

+0

Siamo spiacenti. Non avrei dovuto usare i distruttori come esempio. Aggiornato. – jameszhao00

3

riferimento all'esempio aggiornamento:

  1. Sì, b ha un vtable. Nota che b :: func0() è virtuale (sovrascrive a :: func0()), anche se non l'hai etichettato esplicitamente come virtuale. Weird C++ "loophole", credo.
  2. No. Le funzioni non virtuali non risiedono nel vtable.
  3. Vedere 2.
  4. No. Hai sostituito a: func0(); non importa se chiami a :: func0() o no.

Alcune note aggiuntive (compilatore dipendente, ma queste sono generalizzazioni abbastanza comune):

  • Ogni istanza di b avrà un puntatore ad una vtable, perché si sta derivata da una classe che ha funzioni virtuali.
  • Questo sarebbe il caso anche se non è stato definito b :: func0().
  • In questa situazione, il compilatore potrebbe avere le istanze di B punto un vtable statica s', o potrebbe creare una vtable statica per b e riempirlo con i puntatori ai puntatori ai membri del un .
  • ma è ancora necessario , in modo da poter accedere correttamente un'istanza di b tramite un puntatore ad un .
1
  • Se la funzione della classe base è virtuale, allora se si ignora che funzione nella classe derivata è implicitamente virtuale anche se non si specifica in modo esplicito. Se la classe ha una funzione virtuale, allora ha una tabella v.
  • funzioni solo virtuale presenti in vtable, function1 non risiederanno in vtable
  • function2 non risiederà in vtable stesso motivo di cui sopra
  • Creazione di vtable non dipende dal fatto che si chiami la funzione dalla classe di base o da qualche altra parte . La chiamata di funzione non decide la creazione di vtable.