2009-10-28 12 views
11

ho una classe denominata MyBase che ha un costruttore e distruttore:Il costruttore e il distruttore di una classe base vengono chiamati con quelli derivati?

class MyBase 
{ 
public: 
    MyBase(void); 
    ~MyBase(void); 
}; 

e ho una classe chiamata Banana, che si estende MyBase in questo modo:

class Banana:public MyBase 
{ 
public: 
    Banana(void); 
    ~Banana(void); 
}; 

fa la realizzazione del nuovo costruttore e il distruttore in Banana sovrascrive quelli di MyBase, o esistono ancora e vengono chiamati prima o dopo l'esecuzione del costruttore/distruttore Banana?

Grazie, e le mie scuse se la mia domanda sembra sciocca.

+9

I due modi migliori per ottenere risposte a semplici domande C++: 1) scrivere un semplice caso di test (ad esempio, mettere Couts nei costruttori e distruttori), e 2) vedere se è risposto a http: // www. parashift.com/c++-faq-lite/ – Artelius

+0

Di solito aiuta ad avere la domanda rilevante per ciò che stai chiedendo, invece di far guardare a tutti la descrizione per vedere cosa stai effettivamente chiedendo. –

+0

Questo codice non verrà compilato per una serie di motivi. Cioè una classe Banana non può avere un distruttore "~ MyBase()". Si prega di verificare il codice, prima di pubblicare. –

risposta

6

Si dovrebbe dire

class Banana : public MyBase 
{ 
public: 
    Banana(void); 
    ~Banana(void); 
}; 

Il costruttore della classe derivata viene chiamato dopo il costruttore della classe base. I distruttori vengono chiamati in ordine inverso.

2

Ti manca il tipo di ereditarietà:

Change

class Banana:MyBase 

A:

class Banana: public MyBase 

Per quanto riguarda

fa l'attuazione del nuovo costruttore e d l'estructor in Banana sovrascrive quelli MyBase, oppure esistono ancora e vengono chiamati prima dello o dopo l'esecuzione del distruttore Banana/ ?

L'ordine di esecuzione ereditata dal basso verso l'alto, significa che MyBase verrà chiamato prima, quindi Banana. Se tu avessi un'altra sottoclasse, sarebbe chiamata per ultima.

Prendete questo esempio:

class RottenBanana : public Banana 

La catena di ereditarietà è ora RottenBanana -> Banana -> MyBase

I costruttori di questa classe saranno chiamati a partire da MyBase, quindi Banana e quindi chiamando RottenBanana.

+2

Il tipo di ereditarietà è facoltativo, quando non lo si specifica, sarà l'ereditarietà "privata" per le classi e "pubblica" per le strutture (lo stesso livello di accesso predefinito di tutti i membri). Inoltre, la risposta è un po 'imprecisa con la catena di chiamata del costruttore: la lista di inizializzazione dell'oggetto più derivato è la prima cosa che avvia l'esecuzione, che concatenerà con una chiamata implicita o esplicita al suo costruttore base, l'elenco di inizializzazione di quel costruttore si avvierà e così via ... il primo costruttore da completare sarà il costruttore MyBase come si afferma, quindi in basso la gerarchia –

14

Un costruttore Base verrà sempre chiamato prima del costruttore derivato. Il distruttore Base verrà chiamato dopo il distruttore Dervided.

È possibile specificare sul costruttore derivato quale costruttore Base si desidera, in caso contrario verrà eseguito quello predefinito.

Se si definiscono altri costruttori ma non di default e non si specifica su Costruttore derivato quale da eseguire, verrà tentato il default che non esiste e la compilazione verrà interrotta.

Quanto sopra accade perché una volta che si dichiara un costruttore non vengono generati costruttori predefiniti.

7

I costruttori non possono essere sostituiti. Non è possibile dichiarare un costruttore della classe base in una classe derivata. Un costruttore di classe deve chiamare un costruttore nella classe base (se uno non è esplicitamente dichiarato, viene chiamato il costruttore predefinito) prima di qualsiasi altra cosa.

Per essere in grado di ripulire la classe derivata in modo corretto, è necessario dichiarare il distruttore della classe base come virtual:

virtual ~MyBase() { ... } 
+3

Il distruttore non sarà realmente sovrascritto. La parola chiave virtuale crea una voce nella tabella del metodo virtuale in modo che il distruttore più derivato venga chiamato per primo anche quando si cancella attraverso un puntatore a una classe base. Ma tutti i distruttori di basi saranno chiamati dopo che il distruttore più derivato è stato completato. Cioè, non sovrascrive, garantisce solo che il distruttore più derivato riceve chiamate in tutte le situazioni. –

+0

@dribeas: vero. Modificato per evitare confusione. Ovviamente, sta tecnicamente sovrascrivendo un metodo virtuale. Tuttavia, proprio come la funzione call to base class che è richiesta ed è inserita automaticamente dal compilatore se uno non è esplicitamente dichiarato, la chiamata del distruttore di base verrebbe inserita nel distruttore sovrascritto; chiamare efficacemente il distruttore di base dopo che l'implementazione derivata è terminata. –

3

I costruttori sono chiamati dall'alto in basso nell'albero di ereditarietà. Questo è così che il costruttore derivato può contare sull'oggetto di base completamente inizializzato prima di provare a utilizzare le proprietà della base.

I distruttori vengono chiamati nell'ordine inverso dei costruttori, per lo stesso motivo: le classi derivate dipendono dalla base, ma la base non dipende dal derivato.

Se non v'è alcuna possibilità di distruggere l'oggetto attraverso un puntatore a una classe base, è necessario dichiarare tutti i distruttori virtual.

4

I costruttori e i distruttori sono funzioni membro speciali. In generale si legge ovunque che la costruzione inizia dal tipo meno derivato nella gerarchia fino al tipo più derivato. Questo è in realtà l'ordine in cui l'esecuzione del costruttore viene completata, ma non il modo in cui viene avviata la costruzione.

Costruttori lista di inizializzazione ordine di esecuzione garantisce che mentre costruttore dell'oggetto più derivato sarà il primo costruttore per avviare l'esecuzione sarà l'ultimo costruttore per completare

Quando si crea un'istanza di un oggetto il costruttore più derivato che corrisponde la chiamata di costruzione viene chiamata per prima. Viene avviato l'elenco di inizializzazione del costruttore più derivato con corrispondenza e gli elenchi di inizializzazione hanno un ordine fisso: in primo luogo vengono richiamati i costruttori delle classi di base nell'ordine o nell'aspetto all'interno dell'elenco di ereditarietà. Quindi i costruttori di attributo membro vengono chiamati nell'ordine in cui appaiono nella dichiarazione di classe (non nell'ordine in cui compaiono nell'elenco di inizializzazione). Una volta completato l'intero elenco di inizializzazione (ad ogni livello), viene eseguito il blocco del corpo del costruttore, al termine del quale viene completata la chiamata del costruttore.

Tutti i distruttori di base verranno chiamati in ordine inverso di costruzione dopo che il distruttore più derivato ha completato l'esecuzione. La distruzione avviene in ordine inverso di costruzione.

I distruttori sono speciali in un modo diverso: non possono essere sostituiti. Quando chiamate il distruttore più derivato di una classe, completerà l'esecuzione del corpo del distruttore, dopo di che tutti i distruttori dell'attributo membro verranno chiamati in ordine inverso alla creazione. Dopo che il distruttore più derivato ha completato e così fatto i membri distruttori dell'oggetto più derivato, il distruttore delle sue basi più dirette si avvia in ordine inverso di costruzione, i corpi del distruttore verranno eseguiti, quindi il membro attribuisce i distruttori e così via. Alla fine tutti gli elementi costruiti saranno distrutti.

distruttori di classi polimorfiche dovrebbe essere virtuale

La descrizione sopra distruzione inizia con la chiamata al distruttore massima derivazione.Questo può essere ottenuto chiamando delete su un puntatore al tipo più derivato, quando un oggetto automatico esce dall'oscilloscopio o quando l'oggetto è delete d attraverso una classe base il cui distruttore è virtuale.

Se si dimentica di aggiungere la parola chiave destructor nella classe base e si tenta di eliminare un oggetto derivato tramite un puntatore alla base, si chiamerà direttamente il distruttore di base e ciò implica che tutti gli oggetti secondari sotto il puntatore digitano la gerarchia non sarà adeguatamente distrutta. Tutte le gerarchie di ereditarietà in cui si eliminano gli oggetti tramite puntatori a un tipo di base devono avere distruttori virtuali. Come regola generale, se hai già un metodo virtuale, il costo di rendere virtuale il distruttore è trascurabile ed è una rete sicura. Molte guide di codifica impongono che i distruttori nelle gerarchie di ereditarietà siano virtuali. Alcuni arrivano addirittura a richiedere la virtualizzazione di tutti i distruttori, con l'intenzione di evitare possibili perdite di risorse al costo di aggiungere un vtable per tutti i tipi e un puntatore vtable per tutti gli oggetti.

-2

Se si crea un'istanza di un oggetto EEGModeRGB (a cui sono collegati i led tricolore), quindi eliminarlo immediatamente si vedranno i colori Blu, Verde, Giallo e Rosso, per un secondo ciascuno - in questo ordine.

class EEGMode { 
public: 

    EEGMode() { setAllPixelsToColor(BLUE); delay(1000); } 
    virtual ~EEGMode() { setAllPixelsToColor(RED); delay(1000); } 

}; 


class EEGModeRGB : public EEGMode { 
public: 

    EEGModeRGB() { setAllPixelsToColor(GREEN); delay(1000); } 
    virtual ~EEGModeRGB() { setAllPixelsToColor(YELLOW); delay(1000); } 

}; 
Problemi correlati