2009-12-17 16 views
8

C'è un idioma C++ meno comune che ho usato con buoni risultati alcune volte in passato. Non riesco a ricordare se ha un nome generalmente usato per descriverlo.Derivazione Just-In-Time

È in qualche modo correlato a mixins, CRTP e type-erasure, ma non è specificamente una di quelle cose.

Il problema si verifica quando si desidera aggiungere un'implementazione a una classe, ma non si desidera inserirlo nella classe nella classe o in qualsiasi classe da essa derivata. Una ragione potrebbe essere che la classe potrebbe essere parte di una gerarchia di ereditarietà in cui l'implementazione dovrebbe avvenire solo una volta.

Accantonando, per il momento, problemi come se una gerarchia dovrebbe avere classi concrete non foglia o se l'ereditarietà virtuale può essere un'opzione in alcuni casi, so che una soluzione per fornire l'implementazione in un modello classe che deriva dal suo parametro template. Questo ti consente quindi di usare il modello quando crei un'istanza, ma poi usa sempre l'oggetto solo con il puntatore o con il riferimento a una delle sue basi (è qui che entra in scena la cancellazione del testo, in senso ampio).

Un esempio potrebbe essere il numero di riferimenti intrusivi. Tutte le tue classi derivano da un'interfaccia di conteggio ref, ma vuoi solo che il conteggio ref stesso e l'implementazione dei tuoi metodi di conteggio ref vengano visualizzati una volta, quindi li metti nel template derivato - chiamiamolo ImplementsRC<T>. Ora è possibile creare un'istanza in questo modo:

ConcreteClass* concrete = new ImplementsRC<ConcreteClass>(); 

io sto passando sopra le cose come costruttori di inoltro formate da più sovraccarichi su modelli ecc

Così, si spera che ho messo in chiaro ciò che il linguaggio è. Ora tornando alla mia domanda - c'è un nome accettato, o almeno generalmente usato per questo idioma?

+0

Sembra in qualche modo correlato al pattern Visitor o al Polymorphism esterno ... ma non del tutto. –

+0

Non vedo davvero come sia collegato a uno di quei modelli - cura di elaborare? – philsquared

+0

In che modo non è CRTP? –

risposta

1

Considererei sicuramente questo come un mixin, come farebbe Bruce Eckel (http://www.artima.com/weblogs/viewpost.jsp?thread=132988).

A mio parere, una delle cose che rende questo un mixin è che è ancora un'ereditarietà singola, che è diversa dall'utilizzo di MI per ottenere qualcosa di simile.

+0

Ok, sono convinto. Mi piacerebbe comunque differenziare questo da un mixin "standard" di MI, comunque. Segnalo come la risposta accettata perché è stato l'articolo di Eckel a convincermi, ma tecnicamente Itay ha spinto per Mixin prima – philsquared

0

Sembra Pimpl idiom? Forse usato in un modo insolito.

+0

No, non è proprio un pImpl. Questo è solo per spostare le viscere dell'implementazione per minimizzare le dipendenze - questo è rimandarlo a una classe che è stata usata solo nel momento dell'istanziazione. – philsquared

1

Non sono sicuro che questo abbia un nome, dato che gf ha suggerito che sembra un po 'come il pattern del bridge. È quasi come l'aggancio della funzionalità alla classe base.

Suggerisco un nuovo nome per questo, l'idioma pimp. Mentre stai sfruttando la tua classe base;)

+0

+1 per suggerire l'idioma del pappone :-) Se dovessimo coniare il nome qui mi piace quello. Sfortunatamente dovrei anche rifiutarlo perché c'è troppo spazio per la confusione con l'idioma pImpl ;-) in Bridge, vedi la mia risposta ai commenti di gf. – philsquared

0

Non sono sicuro ma è "l'ottimizzazione C++ del membro vuoto"?

e tale tipo di comportamento è implementato utilizzando modelli di classe e ereditarietà privata.

È spiegato nell'articolo di rivista "Contare gli oggetti in C++" di Scott Meyer.

+0

L'articolo di Scott parla di CRTP. Riguarda la "inversa" di CRTP (cioè 'template struct Derived: T {};' vs 'struct Derived: base pubblica {};') – philsquared

1

Stai cercando il Decorator pattern?

Fondamentalmente il decoratore è un oggetto che racchiude un altro oggetto e estende la funzionalità di determinati metodi. Le chiamate al metodo vengono quindi inoltrate al metodo incluso.

+0

C'è sicuramente qualche risonanza con Decorator, così come ce ne sono alcuni con Ponte. Ma Decorator è specificamente una cosa runtime ed è destinato ad essere alternativo a un approccio di sottoclassi. La forza del decoratore è che consente di fornire numerose decorazioni, mentre il mio approccio ne fa una sola alla volta, anche se potrei prevedere un modello di portamonete generalizzato che potrebbe ottenere ciò. Anche in questo caso, è un nome di livello idiomico che sto cercando, non un livello di pattern. – philsquared

+0

In realtà, nulla impedisce che la tua idea venga applicata in modo ricorsivo: 'ConcreteClass * cc = new ImplementA >();', a condizione di derivare sia da 'InterfaceA' che da' InterfaceB'. Tuttavia, Decorator significa arricchire una funzionalità esistente mentre nel tuo approccio la funzionalità non esiste prima. –

1

Questo è un mixin

+0

Anche se certamente condivide alcuni aspetti dei mixin, l'ho deliberatamente escluso. Dall'articolo di wikipedia a cui mi sono collegato (sento di contraddire questo - c'è una definizione autorevole da qualche parte?) Dice, "un mixin è una classe che fornisce una certa funzionalità per essere ereditata da una sottoclasse, mentre non è pensata per l'istanziazione". In entrambi i casi, l'idioma di cui sto parlando rovescia la situazione. È la classe generica che sottoclasse la classe specifica (la terminologia scomoda lì) ed è pensata per l'istanziazione. Forse la classe base è il mixin, ma non è quello che mi serve per il nome. – philsquared

+0

Non sono d'accordo con la definizione di Wikipedia. Ecco un lavoro accademico sui mixin: http://www.disi.unige.it/person/LagorioG/jam. Esaminando la dichiarazione: "class ExampleWithUndo = Undo extends Example {}" (alla fine del secondo snippet), dove Undo è un mixin, sembra equivalente al 100% a typedef ImplementsRC MyNewType; –

+0

Molto interessante. Ciò sembra corrispondere più fortemente. Non sono sicuro * I * sono d'accordo con l'uso di mixin da parte dei siti, tuttavia :-) La classe dell'erede suona come un termine più utile, comunque. Grazie per il link. – philsquared

3

È un'idea interessante.Comunque non ho intenzione di darti il ​​nome di uno schema già stabilito qui, al contrario sto per spiegare (in qualche modo) perché non penso che ne abbia già uno.

Cosa fa?

È un modo molto carino per evitare l'eredità del terribile diamante.

Poiché non v'è una certa confusione a quanto pare per lo scopo del metodo, Vorrei esporre il motivo per cui credo che questo è il suo scopo:

class RefCounted 
{ 
    virtual void addReference() = 0; 
    virtual void removeReference() = 0; 
}; 

class B: public RefCounted {}; 
class C: public RefCounted {}; 

class Diamond: public B, public C {}; 

Ora, noi qui hanno un problema. Se inseriamo l'implementazione di RefCounted proprio in questa classe, diventa una classe base anziché un'interfaccia, e quindi dobbiamo usare l'ereditarietà virtuale oi membri dei dati saranno duplicati (presenti sia in B che in C).

L'idea è quindi di posticipare l'implementazione all'ultimo momento.

Vantaggi:

  • Non c'è bisogno di cercare di indovinare l'uso di B o C: ereditarietà virtuale è inutile lì.
  • Il compilatore ricorderà bene se si dimentica di aggiungere l'implementazione, quindi non è necessario preoccuparsi di ciò.

scomoda:

  • Mettere l'onere per il cliente: è meglio avere una fabbrica per creare gli oggetti, tanto più che un oggetto può implementare diverse interfacce !!! Si noti che questo potrebbe essere automatizzato con la meta-programmazione dei modelli (più o meno) o può essere semplicemente fornita dall'autore della classe.

Esempio di fornire:

// d.h 
class D: public B, public C 
{ 
public: 
    typedef ImplementRC<D> concrete_type; 
    static concrete_type Build(int, int); // Named Constructor idiom 

private: 
    D(int,int); 
}; // class D 

// main.cpp 
D::concrete_type myD = D::Build(1,2); 

Allora qual è il nome?

Non riesco a pensare a qualcosa che corrisponda esattamente a questo. Bridge e Decorator sono stati menzionati ma questo è abbastanza speciale, e in effetti non è così orientato all'OO (ad esempio non succederà in Java poiché non hai Multi-Inheritance), quindi dubito che il termine sarà trovato nel libro dei GoF.

Inoltre, non è proprio il CRTP perché esiste un tipo di loop nel CRTP (la base è consapevole della sua classe derivata) che non accade qui> siamo infatti rigorosamente lineari!

E quindi, non è certamente l'idioma Pimpl, che propone di nascondere l'implementazione dal client mentre utilizza un modello per l'implementazione, basta lanciarlo in faccia! (Il modello potrebbe usare Pimpl come un dettaglio interno però)

umilmente suggerire jiti per Just In Time Attuazione, che imita il titolo in qualche modo, ma è più vicino al punto penso, derivazione qui essere solo un strumento piuttosto che un obiettivo.

Interessante idea comunque.

+0

Grazie Matthieu. Sicuramente sembra aver afferrato il design. E sì, è in gran parte un modo per evitare il problema dell'ereditarietà del diamante senza ereditarietà virtuale. JITI è un nome interessante. Non sono sicuro che sia davvero migliore o peggiore del mio, sebbene abbia almeno un acronimo più pronunciabile ;-) – philsquared

1

Osservando l'esempio di conteggio dei riferimenti, è possibile ottenere un po 'di piacere guardando CComObject <> che è una delle poche classi di template che ATL contiene per fornire l'implementazione di IUnknown. Utilizza inoltre le classi di politica per variare il comportamento. Naturalmente il rapporto segnale-rumore che prova su Google sul concetto di CComObject è molto basso perché è così onnipresente. Questo articolo MSDN potrebbe fornire alcune "parole chiave" aggiuntive per facilitare qualsiasi ricerca.

http://msdn.microsoft.com/en-us/library/c43h4867(VS.80).aspx

[NB: Giusto per essere chiari - non sto suggerendo che usa CComObject, sto suggerendo che è un altro esempio popolare dello stesso concetto e, pertanto, potrebbe essere stato fatto riferimento in un pattern libro o articolo]

+0

Grazie, Chris. Penso che "CComObject <>" sia probabilmente uno dei primi esempi che ho visto di questo idioma in uso. Non ricordo che Microsoft abbia mai fatto riferimento ad esso come un idioma chiamato, tuttavia - e uno sguardo veloce all'articolo collegato non suggerisce nulla di diverso. – philsquared

0

Rispondere alla mia domanda. Primo segno di follia? - no ci sono stati diversi segnali prima di questo ;-)

In ogni caso, è passato tanto tempo da quando ho pubblicato originariamente sono più o meno una persona diversa comunque.

Ho trovato che ho definito il nome, mixover. Ho trovato questo si adatta molto bene e può essere considerato una raffinatezza di mixin, piuttosto che essere esclusivo per il concetto più generale.

Ho usato molto recentemente, quindi ho pensato di tornare e aggiornare questo thread.