Domanda

Ho una classe base con una funzione virtuale e voglio sovrascrivere quella funzione in una classe derivata. Esiste un modo per fare in modo che il compilatore controlli se la funzione che ho dichiarato nella classe derivata sovrascrive effettivamente una funzione nella classe base? Vorrei aggiungere alcune macro o qualcosa che assicuri che non ho dichiarato accidentalmente una nuova funzione, invece di sovrascrivere quella precedente.

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 invece di child::handle_event(), perché il metodo del bambino manca la dichiarazione const e quindi dichiara un nuovo metodo. Questo potrebbe anche essere un errore di battitura nel nome della funzione o qualche piccola differenza nei tipi di parametri. Può anche accadere facilmente se l'interfaccia della classe base cambia e da qualche parte una classe derivata non è stata aggiornata per riflettere la modifica.

Esiste un modo per evitare questo problema, posso in qualche modo dire al compilatore o qualche altro strumento di verificarlo? Qualche utile flag del compilatore (preferibilmente per g ++)? Come evitare questi problemi?

È stato utile?

Soluzione

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

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;
};

Altri suggerimenti

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

In gcc, -Woverloaded-virtual mette in guardia dal nascondere una funzione virtuale di classe base con una funzione con lo stesso nome ma una firma sufficientemente diversa da non sovrascriverla. Tuttavia, non ti proteggerà dal mancato superamento di una funzione a causa di un'ortografia errata 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
  }
};

Pensavo di aver letto su 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 in merito al fatto che non può avere un'implementazione stessa.

In MSVC, puoi utilizzare la parola chiave CLR override anche se non stai compilando per CLR.

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

In MSVC ++ puoi usare parola chiave override

    class child : public parent {
    public:
      virtual void handle_event(int something) override {
        // new exciting code
      }
    };

<=> funziona sia per codice nativo che CLR in MSVC ++.

Rendi la funzione astratta, 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 funzionare o meno, a seconda di ciò che devi realizzare.

handle_event () può ancora fare il " noioso codice predefinito " ma invece di essere virtuale, nel punto in cui vuoi che faccia il " nuovo eccitante codice " chiedi alla classe base di chiamare un metodo astratto (cioè deve essere ignorato) che verrà fornito dalla tua classe discendente.

EDIT: E se in seguito decidi che alcune delle tue classi discendenti non devono fornire " nuovo codice eccitante " quindi puoi cambiare l'abstract in virtuale e fornire un'implementazione vuota della classe base di quel " inserito " funzionalità.

Il compilatore potrebbe avere un avviso che può generare se una funzione della classe base viene nascosta. In tal caso, abilitalo. Ciò rileverà scontri costanti e differenze nelle liste di parametri. Sfortunatamente questo non scoprirà un errore di ortografia.

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top