2012-11-19 15 views
13

Supponiamo che io ho il seguente codice:Perché devo ri-dichiarare le funzioni sottoposte a override nelle classi derivate in C++?

class Iinterface 
{ 
    virtual void abstractFunction()=0; 
}; 

class Derived : public Iinterface 
{ 
    void abstractFunction(); // Do I need this line? 
}; 

Derived::abstractFunction() 
{ 
    // implementation here 
} 

Se non aggiungo la linea in questione, ottengo errore di compilazione che dice abstractFunction non è dichiarata nel Derived. Sto usando VS 2008.
Non sono sicuro del motivo per cui ho bisogno di questa particolare riga (non confondere questo con la definizione di funzione fornita all'esterno della dichiarazione di classe), a patto che io stia ereditando da Iinterface essere ovvio che ho dichiarato abstractFunction. È un problema con Visual Studio o è applicato da standard C++?

risposta

8

Se la dichiarazione delle funzioni di base puramente virtuali era implicita in tutte le classi derivate, non si può mai avere una classe derivata che rimanga astratta rispetto a una funzione di base puramente virtuale. Invece, tutte le classi derivate produrranno errori di linker. Ciò sarebbe estremamente contro-intuitivo e confuso e renderebbe il linguaggio meno espressivo.

Inoltre, non avrebbe nemmeno senso: la domanda se la classe derivata è astratta o meno deve essere conosciuta ovunque in fase di compilazione. L'implementazione dell'overrider viene tipicamente fornita solo in una singola unità di traduzione, quindi sarebbe impossibile comunicare il fatto che in realtà si intende che la funzione venga sovrascritta al resto del programma.

+0

hai riassunto molto meglio :) –

+0

Sono d'accordo, questo è probabilmente più comprensibile della mia risposta vagante, +1. – OmnipotentEntity

+0

Se la classe derivata è astratta o non può essere conosciuta con una parola chiave "astratta" esplicita che manca in C++. –

0

Sì, l'intero scopo di una pura funzione virtuale è far valere che lo si sovrascrive nella classe derivata; tale dichiarazione deve essere esplicito in C++

+0

Sono consapevole di ciò, e io ** lo sto ** sovrascrivendo, ma non capisco perché ho bisogno di riscrivere il prototipo della funzione all'interno della dichiarazione di classe. Perché VS non lo dedurrà da solo? – atoMerz

+0

VS pensa che ci si sia dimenticati del metodo :) – whd

+0

Poiché la definizione della classe guida la progettazione della gerarchia degli oggetti, se lo si desidera; come illustrato in precedenza, la scelta se includere o meno la dichiarazione di override indica al compilatore se il codice del metodo corrispondente deve essere presente oppure no. –

2
  1. : Se si desidera creare un oggetto della class Derived
  2. No: Se si desidera mantenere la class Derived anche astratto
  3. No: Se esiste una classe intermedia che ha già scavalcato la funzione
    es. tra Iinterface e Derived c'è un class Intermediate che ha sostituito abstractFunction(); Quindi ora è facoltativo per class Derived di ignorare la stessa

Edit: Con il titolo della domanda mutato,

Perché devo ri-dichiarare le funzioni override nelle classi derivate in C++?

Questo perché C++ grammatica compilatore richiede che ogni funzione membro della class (o namespace o file) deve essere dichiarato all'interno del corpo class (o namespace o file). Be it virtual o funzione normale.
C'è no una buona ragione per rompere quella coerenza solo per le funzioni virtual.

+1

Penso che l'OP sia consapevole della meccanica di ignorare una funzione di base puramente virtuale. Vuole sapere perché la * dichiarazione * è necessaria nella classe derivata. –

+0

@ KerrekSB Grazie, è quello che intendevo esattamente. – atoMerz

+0

@KerrekSB, sembra che il titolo della domanda sia stato modificato proprio ora. Modificherò la risposta. – iammilind

1

Una funzione che si conclude in un =0 è chiamato deleted function, questo è utile quando non si desidera che gli oggetti che utilizzano alcuni costruttori (come ad esempio unique_ptr che ha un ctor copia eliminata).

Se una funzione virtual viene cancellata, la classe diventa di tipo astratto per standard. Poiché nella maggior parte dei casi il prototipo di una classe e i corpi delle funzioni della classe si trovano in file separati, ciò significa che, a meno che non specifichi esplicitamente nel prototipo che stai ignorando la funzione virtuale eliminata, NON stai sovrascrivendo la funzione virtuale eliminata. Il compilatore non dovrebbe semplicemente dedurre semplicemente che intendevi inserire la funzione una volta che vede l'implementazione in un file completamente diverso.

Ricordare che l'idea di prototipo/implementazione non è l'unico modo per scrivere codice, è anche possibile inserire l'implementazione direttamente nella classe (che può essere eseguita se il codice è abbastanza piccolo e si desidera incorporare la funzione.) E per fare ciò è necessario, di nuovo, sovrascrivere esplicitamente la funzione virtuale eliminata. Quindi, poiché è necessario sovrascriverlo in ogni caso, è perfettamente logico che sia necessario sovrascriverlo esplicitamente nel prototipo. La funzione è ancora cancellata in caso contrario.

Per un esempio concreto: supponiamo di avere un List.hpp, List.cpp e main.cpp

In List.hpp si dispone di una classe astratta e una classe normale che eredita dalla classe astratta. In main è #include "List.hpp" e non List.cpp, giusto? Quindi il compilatore NON ha IDEA in quel file (fino a quando non tenta di compilarlo). Se non si ha la funzione virtuale eliminata sovrascritta, il compilatore pensa che si stia semplicemente tentando di creare un'istanza di una classe astratta e di generare un errore.

D'altra parte, se si sta compilando List.cpp, anche il compilatore genererà un errore, questa volta lamentandosi che la funzione che si sta tentando di scrivere non sia stata effettivamente definita. Perché Base::deletedFunction() è diverso da Derived::deletedFunction().

+0

Grazie. Si tratta di una limitazione del compilatore o di una limitazione C++? – atoMerz

+1

Limitazione C++. Anche se esiterei a chiamarlo una limitazione. È semplicemente che devi essere esplicito al riguardo. Che ti aiuta a lungo termine, imo. – OmnipotentEntity

Problemi correlati