Funzionalità aumentante di sottoclassi senza duplicazione del codice in C ++

3

Devo aggiungere funzionalità comuni ad alcune classi che condividono la stessa superclasse, preferibilmente senza gonfiare la superclasse. La catena di ereditarietà semplificata ha questo aspetto:

Element -> HTMLElement -> HTMLAnchorElement
Element -> SVGElement -> SVGAlement

Il metodo predefinito doSomething() su Element è non operativo per impostazione predefinita, ma esistono alcune sottoclassi che richiedono un'implementazione effettiva che richiede alcuni metodi e membri di istanze sottoposti a override aggiuntivi. Non riesco a mettere una piena implementazione di doSomething() in Element perché 1) è rilevante solo per alcune sottoclassi, 2) la sua implementazione ha un impatto sulle prestazioni e 3) dipende da un metodo che può essere sovrascritto da una classe nella catena ereditaria tra la superclasse e una sottoclasse, ad es SVGElement nel mio esempio.

Specialmente a causa del terzo punto, volevo risolvere il problema usando una classe template, come segue (è una specie di decoratore per le classi):

struct Element {
    virtual void doSomething() {}
};

// T should be an instance of Element
template<class T>
struct AugmentedElement : public T {
    // doSomething is expensive and uses T
    virtual void doSomething() override {}
    // Used by doSomething
    virtual bool shouldDoSomething() = 0;
};

class SVGElement : public Element { /* ... */ };
class SVGAElement : public AugmentedElement<SVGElement> {
    // some non-trivial check
    bool shouldDoSomething() { /* ... */ return true; }
};
// Similarly for HTMLAElement and others

Mi sono guardato intorno (nella già esistente (enorme) base di codice e su internet), ma non ho trovato frammenti di codice simili, per non parlare di una valutazione dell'efficacia e delle insidie di questo approccio.

Il mio design è la strada giusta da percorrere, oppure esiste un modo migliore per aggiungere funzionalità comuni ad alcune sottoclassi di una determinata superclasse?

    
posta Rob W 21.08.2014 - 17:22
fonte

1 risposta

3

Lo stai facendo correttamente. Il fatto è chiamato un mixin ed è piuttosto comune.

La ricerca rapida mostra per es. Che cosa sono i Mixin (come concetto) o Qual è lo stile Mixin C ++? . Si tratta del modello di template che ricorre in modo curioso , il cui nome deriva anche dal fatto che è, beh, ricorrente .

Nel tuo caso, l'utilizzo di CRTP completo ti consente di evitare il virtuale:

template<typename BaseT, typename DerivedT>
struct AugmentedElement : public BaseT {
    // doSomething is expensive and uses T
    virtual void doSomething() override {
        // do stuff
        static_cast<DerivedT *>(this)->shouldDoSomething();
        // do more stuff, etc.
    }
};
    
risposta data 21.08.2014 - 17:56
fonte

Leggi altre domande sui tag