Vorrei sottolineare una cosa prima di condividere parte della mia esperienza. Si prega di fare attenzione a dire astratte classi di base e interfacce così liberamente a fianco. Gli ABC sono un concetto di linguaggio e Interface è un concetto di design. Ovviamente gli ABC sono molto utili nell'implementazione delle interfacce in c++
, tuttavia non penso che sia stato detto da nessuna parte (fonte altamente credibile) che sono pensati specificamente per questo. Ci sono altri modi per farlo! Per favore, leggi un link .
Detto questo, per rispondere alla tua domanda. Nella mia esperienza come regola generale dovresti sempre scrivere codice che ritieni sia stato progettato bene. Se pensi che i virtuals bloccheranno le tue prestazioni, seriamente non preoccuparti se non puoi dimostrare che è superiore al 10% se prevedi di gestire il tuo codice. Se è one-shot, spremere tutto, la progettazione del codice non ha importanza.
Purtroppo bisogna imparare come analizzare e profilare le applicazioni, a un livello che ritengo abbastanza elevato, per riprogettare correttamente il codice. Dovresti essere in grado di dire se hai bisogno di riorganizzare le filiali, eliminare i virtual o la gestione della memoria o trovare colli di bottiglia. Credo che oggigiorno siano molto più spesso legati all'hardware. Se osservi alcune domande relative alle prestazioni di SO c++
, vedrai che i colli di bottiglie hanno mentito in posti molto strani e solo le persone che hanno profilato il codice per le mancate cache o le previsioni delle branchie sono stati in grado di trovare le cause.
Devo dire che sono caduto vittima di ottimizzazioni pre-mature, oltre che di under e over-design. Ho cercato di implementare (diamine, ho implementato) cose intelligenti dove non erano necessarie, e solo complicato codice e sistema di interfaccia a un punto in cui non era divertente estendere i miei programmi. Per velocizzare il 5%, ho effettivamente ostacolato il processo di test fino al punto in cui ho dovuto trascorrere un giorno per implementare i test o testarlo manualmente dopo l'aggiunta di alcune nuove funzionalità. Sono anche passato a cose come get_x(){ return x;};
era virtual
perché condivideva l'interfaccia con qualcosa che aveva una diversa gestione della memoria.
Per riassumere, per ora il mio consiglio sarebbe :
-
Scrivi un codice che è ben progettato per le esigenze attuali (e forse per il futuro immediato). Non cercare di complicarlo troppo prima. È altrettanto brutto delle premature occasioni. Esperienza personale.
-
Quando è appropriato, quindi refactoring e introduce modelli.
-
Non preoccuparti delle prestazioni, a meno che tu non sia sicuro di averne bisogno. Impara ad analizzare il tuo codice ad alta qualità. Quindi lavora sui colli di bottiglia.
Ovviamente il suo lavoro probabilmente è il doppio rispetto a ottenere tutto giusto al 1 ° posto. Nel mio caso il problema è che mi manca il right
modo 2 su 3 volte se non di più :). Credo che nel tempo un buon programmatore sia in grado di scegliere un buon approccio in anticipo più spesso.
Nei modelli contro gli ABC per le interfacce.
Penso che gli ABC siano più programmabili e leggibili, tuttavia mi piacerebbe avere il polimorfismo dei template se mi imbattessi in qualcosa del tipo:
...
virtual get_x() {return coords[0];};
virtual get_y() {return coords[1];};
virtual get_z() {return coords[2];};
...
void some_fancy_algorithm_that_work_on_coords(){
// for example calculate distances between every pair of instances
// that can provide 'ICoords' interface
}
Il polimorfismo di base di template I un compilatore semi-decente può eliminare i cast di oggetti impliciti e utilizzare direttamente metodi e proprietà di riferimento. È bene evitare i virtual e l'accesso intermedio, anche se tutto è racchiuso nella progettazione del codice.