Domanda

Quali sono alcuni usi pratici per il " Pattern dei modelli curiosamente ricorrente " ;? Il " classe conteggiata " l'esempio comunemente mostrato non è per me un esempio convincente.

È stato utile?

Soluzione

Rilegatura dinamica simulata . Evitare il costo delle chiamate di funzione virtuale pur mantenendo alcuni dei vantaggi gerarchici è una vittoria enorme per i sottosistemi in cui può essere fatto nel progetto su cui sto attualmente lavorando.

Altri suggerimenti

È anche particolarmente utile per i mixin (con cui intendo le classi da cui erediti per fornire funzionalità) che essi stessi devono sapere su quale tipo stanno operando (e quindi devono essere modelli).

In C ++ efficace , Scott Meyers fornisce come esempio un modello di classe NewHandlerSupport < T > ;. Questo contiene un metodo statico per sovrascrivere il nuovo gestore per una particolare classe (allo stesso modo di std :: set_new_handler per l'operatore predefinito new) e un operatore new che utilizza il gestore. Per fornire un gestore per tipo, la classe padre deve sapere su quale tipo agisce, quindi deve essere un modello di classe. Il parametro template è la classe child.

Non si potrebbe davvero farlo senza CRTP, poiché è necessario creare un'istanza del modello NewHandlerSupport separatamente, con un membro di dati statici separato per archiviare l'attuale new_handler, per classe che lo utilizza.

Ovviamente l'intero esempio è estremamente sicuro per i thread, ma illustra il punto.

Meyers suggerisce che il CRTP potrebbe essere considerato come "Do It For Me". Direi che questo è generalmente il caso di qualsiasi mixin, e CRTP si applica nel caso in cui sia necessario un modello di mixin anziché solo una classe di mixin.

Il CRTP diventa molto meno curioso se si considera che il tipo di sottoclasse che viene passato alla superclasse è necessario solo al momento dell'espansione del metodo. Quindi vengono definiti tutti i tipi. Hai solo bisogno del modello per importare il tipo simbolico di sottoclasse nella superclasse, ma è solo una dichiarazione diretta - come tutti i tipi di parametri del modello formale sono per definizione - per quanto riguarda la superclasse.

Usiamo in una forma un po 'modificata, passando la sottoclasse in una struttura di tipo tratti alla superclasse per consentire alla superclasse di restituire oggetti del tipo derivato. L'applicazione è una libreria per il calcolo geometrico (punti, vettori, linee, caselle) in cui tutte le funzionalità generiche sono implementate nella superclasse e la sottoclasse definisce solo un tipo specifico: CFltPoint eredita da TGenPoint. Anche CFltPoint esisteva prima di TGenPoint, quindi la sottoclasse era un modo naturale di refactoring.

Generalmente viene utilizzato per modelli polimorfici in cui non è necessario essere in grado di scegliere la classe derivata in fase di esecuzione, solo al momento della compilazione. Ciò può salvare l'overhead della chiamata di funzione virtuale in fase di esecuzione.

Per un uso della libreria del CRTP nel mondo reale, guarda ATL e WTL (wtl.sf.net). È ampiamente utilizzato lì per il polimorfismo in fase di compilazione.

Sembra una specie di macro C: approfitta del fatto che la macro non viene compilata al momento della definizione, ma al momento dell'uso.

#define CALL_THE_RIGHT_FOO foo()

file A:

static void foo() {
   // do file A thing
}
...
CALL_THE_RIGHT_FOO
...

file A:

static void foo() {
   // do file B thing
}
...
CALL_THE_RIGHT_FOO
...

Il modello di utilizzo del modello che stai descrivendo ci consente di " chiamare il pippo giusto " nel modello genitore, rimandando la definizione di ciò che è esattamente il foo giusto fino a quando il modello non viene istanziato. Tranne che in questo caso è la distinzione tra ClassA :: foo e ClassB :: foo in base al valore di T in Parent.

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