Esclusione sicura delle funzioni virtuali C ++

Ho una class base con una funzione virtuale e voglio sovrascrivere quella funzione in una class derivata. C’è un modo per far sì che il compilatore verifichi se la funzione che ho dichiarato nella class derivata sovrascrive effettivamente una funzione nella class base? Vorrei aggiungere qualche macro o qualcosa che assicuri che non abbia dichiarato accidentalmente una nuova funzione, invece di sovrascrivere quella vecchia.

Prendi questo esempio:

class parent { public: virtual void handle_event(int something) const { // boring default code } }; class child : public parent { public: virtual void handle_event(int something) { // new exciting code } }; int main() { parent *p = new child(); p->handle_event(1); } 

Qui parent::handle_event() viene chiamato al posto di child::handle_event() , perché il metodo del figlio manca la dichiarazione const e quindi dichiara un nuovo metodo. Questo potrebbe anche essere un refuso nel nome della funzione o qualche piccola differenza nei tipi di parametri. Può anche accadere facilmente se l’interfaccia della class base cambia e da qualche parte una class derivata non è stata aggiornata per riflettere la modifica.

C’è un modo per evitare questo problema, posso in qualche modo dire al compilatore o qualche altro strumento per controllare questo per me? Eventuali flag utili per il compilatore (preferibilmente per g ++)? Come eviti questi problemi?

Da g ++ 4.7 capisce la nuova parola chiave override C ++ 11:

 class child : public parent { public: // force handle_event to override a existing function in parent // error out if the function with the correct signature does not exist void handle_event(int something) override; }; 

Qualcosa come la parola chiave override C # non fa parte di C ++.

In gcc, -Woverloaded-virtual avverte di hide una funzione virtuale di class base con una funzione con lo stesso nome ma una firma sufficientemente diversa da non sovrascriverla. Tuttavia, non ti proteggerà dal non riuscire a sovrascrivere una funzione a causa dell’errata ortografia del nome della funzione stessa.

Per quanto ne so, non puoi semplicemente renderlo astratto?

 class parent { public: virtual void handle_event(int something) const = 0 { // boring default code } }; 

Ho pensato di leggere su http://www.parashift.com che puoi effettivamente implementare un metodo astratto. Il che ha senso per me personalmente, l’unica cosa che fa è forzare le sottoclassi a implementarlo, nessuno ha detto nulla al riguardo non avendo il permesso di avere un’implementazione stessa.

In MSVC, è ansible utilizzare la parola chiave override CLR anche se non si sta compilando per CLR.

In g ++, non esiste un modo diretto per far rispettare ciò in tutti i casi; altre persone hanno dato buone risposte su come catturare le differenze di firma usando -Woverloaded-virtual . In una versione futura, qualcuno potrebbe aggiungere la syntax come __attribute__ ((override)) o l’equivalente usando la syntax C ++ 0x.

In MSVC ++ puoi usare l’ override parole chiave

     bambino di class: genitore pubblico {
     pubblico:
       virtual void handle_event (int something) override {
         // nuovo codice eccitante
       }
     };

override funziona sia per codice nativo che CLR in MSVC ++.

Rendi astratta la funzione, in modo che le classi derivate non abbiano altra scelta che sovrascriverla.

@Ray Il tuo codice non è valido.

 class parent { public: virtual void handle_event(int something) const = 0 { // boring default code } }; 

Le funzioni astratte non possono avere corpi definiti in linea. Deve essere modificato per diventare

 class parent { public: virtual void handle_event(int something) const = 0; }; void parent::handle_event( int something ) { /* do w/e you want here. */ } 

Suggerirei un leggero cambiamento nella tua logica. Potrebbe o meno funzionare, a seconda di ciò che è necessario realizzare.

handle_event () può ancora fare il “codice di default noioso” ma invece di essere virtuale, nel punto in cui si desidera che faccia il “nuovo eccitante codice”, la chiamata di class base deve essere un metodo astratto (cioè deve essere sovrascritto) che sarà fornito dalla tua class discendente.

EDIT: E se in seguito decidi che alcune delle tue classi discendenti non devono fornire “un nuovo codice eccitante”, puoi cambiare l’abstract in virtuale e fornire un’implementazione di class base vuota di quella funzionalità “inserita”.

Il compilatore potrebbe avere un avviso che può generare se una funzione di class base viene nascosta. Se lo fa, abilitalo. Ciò colpirà const scontri e differenze negli elenchi di parametri. Sfortunatamente questo non rivelerà un errore di ortografia.

Ad esempio, questo è un avviso C4263 in Microsoft Visual C ++.