Domanda

Ho trovato il seguente codice in una libreria:

class Bar {
public:
  bool foo(int i) {
   return foo_(i);
  }
private:
  virtual bool foo_(int i) = 0;
};

Ora mi chiedo: perché dovresti usare questa indiretta? Potrebbero esserci dei motivi per cui quanto sopra sarebbe meglio della semplice alternativa:

class Bar {
public:
  virtual bool foo(int i) = 0;
};
È stato utile?

Soluzione

Questo è il Idioma di interfaccia non virtuale (NVI). La pagina di Herb Sutter contiene molti dettagli. Tuttavia, tempera ciò che leggi lì con ciò che dice la FAQ C ++ Lite qui e qui .

Il vantaggio principale di NVI è la separazione dell'interfaccia dall'implementazione. Una classe base può implementare un algoritmo generico e presentarlo al mondo, mentre le sue sottoclassi possono implementare i dettagli dell'algoritmo attraverso funzioni virtuali. Gli utenti esterni sono protetti dalle modifiche ai dettagli dell'algoritmo, soprattutto se in seguito decidi di voler aggiungere il codice pre e post elaborazione.

L'ovvio svantaggio è che devi scrivere un codice extra. Inoltre, private le funzioni virtuali confondono molte persone. Molti programmatori pensano erroneamente di non poterli sovrascrivere. Herb Sutter sembra gradire protected i virtuali, ma IMHO è più efficace in pratica seguire le raccomandazioni del C ++ FAQ Lite e renderle <=>.

Altri suggerimenti

Questa è spesso chiamata coppia Template-Hook (a.k.a Hotspot), coniata da Wolfgang Pree.

Vedi questo PDF , PowerPoint , HTML

Uno dei motivi per fare la indiretta come la chiami è che spesso le cose possono / devono essere installate prima di un metodo e alcuni post una chiamata di metodo. Nelle sottoclassi devi solo fornire il comportamento necessario senza fare setup e pulizia ...

Questo è il modello di modello. Il metodo foo contiene codice che deve essere eseguito da tutte le sottoclassi. Ha più senso guardandolo in questo modo:

class Bar {
public:
  bool foo(int i) {
   // Setup / initialization / error checking / input validation etc 
   // that must be done for all subclasses
   return foo_(i);
  }
private:
  virtual bool foo_(int i) = 0;
};

È più bello dell'alternativa, che è cercare di ricordare di chiamare il codice comune in ogni sottoclasse individualmente. Inevitabilmente, qualcuno crea una sottoclasse ma si dimentica di chiamare il codice comune, causando un numero qualsiasi di problemi.

Se una sottoclasse potrebbe cambiare la definizione di foo_?, ma i consumatori necessitavano di una funzione statica (per efficienza)? O per un modello di delega?

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