Domanda

typedef void (FunctionSet::* Function)();

class MyFunctionSet : public FunctionSet
{
protected:
    void addFunctions()
    {
        addFunction(Function(&MyFunctionSet::function1));
    }

    void function1()
    {
        // Do something.
    }
};

Il metodo addFunction aggiunge la funzione a un elenco nella classe base,
che possono quindi essere elencati per chiamare tutte le funzioni.

Esiste un modo per semplificare (meno lavoro di battitura) l'aggiunta di funzioni?

È stato utile?

Soluzione

Sembra che tu assegni un puntatore a funzione membro a una funzione della classe derivata a un puntatore a funzione membro a una funzione della classe base. Bene, è proibito, perché apre un buco nel sistema dei tipi. È una sorpresa (almeno per me, la prima volta che l'ho sentito). Leggi questa risposta per perché.

Per rispondere alla tua vera domanda, farei addFunction un modello:

void addFunctions() {
    addFunction(&MyFunctionSet::function1);
}

Modifica addFunction nella classe base in questo:

template<typename Derived>
void addFunction(void(Derived::*f)()) {
    myFunctions.push_back(static_cast<Function>(f));
}

Meglio usare static_cast , perché ti dirà se Derivato non è effettivamente derivato da FunctionSet .

Altri suggerimenti

Puoi spiegare cosa stai cercando di ottenere facendo questo?

Questo sembra un design piuttosto negativo, non puoi avere una classe astratta ("interfaccia c ++") come "Computabile"? che ha una pura funzione virtuale1, sottoclasse Computable per ogni implementazione e quindi MyFunctionSet mantiene un set di Computable?

C'è un motivo specifico per cui stai usando i puntatori a funzione?

Quindi, in qualche modo, sono in disaccordo con Uri.

Se stai implementando il modello Observer, quello che vuoi è poter dire:

" Quando l'oggetto X fa Y, voglio eseguire il codice Z " ;.

Seguire un approccio basato esclusivamente su una classe astratta non è il modo migliore per farlo. Richiedere una classe separata (specialmente in C ++) per ogni gestore di eventi è eccessivo. Se vieni da Java, è così che fanno tutto. Tuttavia Java ha 2 caratteristiche che lo rendono solo leggermente fastidioso: classe anonima e " istanza " classi membri. Ciò consente di definire più gestori per più eventi nella stessa classe. Devi aggiungere il prefisso ai metodi con " class {" ;, ma puoi farlo.

C ++ non ha classi anonime o " istanza " classi membri. Ciò rende l'utilizzo di una classe astratta per eventi molto più ingombrante se si dispone di più gestori che devono condividere lo stato. Devi fare l'equivalente della generazione della chiusura a mano, che può diventare piuttosto irritante abbastanza rapidamente.

.NET utilizza delegati per la gestione degli eventi, che sono fondamentalmente tipi di puntatori di funzioni sicure. Rendono il codice per la gestione degli eventi molto semplice. A differenza dei puntatori di funzione in C ++, tuttavia, un delegato unifica i puntatori di funzione membro e i puntatori di funzione statica. Fondamentalmente può curry il " questo " parametro di qualsiasi funzione membro, lasciando un puntatore a funzione che assomiglia a un puntatore a funzione statica. Ciò significa che il tipo di oggetto che gestisce l'evento non fa parte dell'evento "interfaccia". Questo lo rende molto flessibile.

Non puoi farlo direttamente usando i puntatori di funzione membro C ++ perché " questo " type finisce per far parte del tipo di puntatore a funzione, limitando così i gestori ad apparire solo all'interno della classe corrente.

La migliore soluzione per C ++ è un ibrido tra i due. Quello che vuoi è un'interfaccia generica come questa:

class EventHandler
{
public:
    virtual void Handle() = 0;
};

E poi un'implementazione per funzioni membro come questa

template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:


    MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
    {
    }

    void Handle()
    {
        (m_pThis->*m_pFunc)();
    } 
private:
    T* m_pThis;
    void (T::*m_pFunc)();
};

template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
    return new MemberFuncEventHandler<T>(pThis, pFunc);
}

Puoi anche definire in modo simile una classe di gestori per metodi statici. Quindi puoi semplicemente fare cose come queste:

Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...

Potrei sovraccaricare l'operatore addizione, suppongo.

Se stai cercando di creare un sistema di callback o qualcosa del genere, consiglierei la libreria Boost.Signals. Fondamentalmente aggrega le funzioni e chiama il gruppo di funzioni su comando (come qualsiasi altra libreria di segnali) ma è anche progettato per funzionare con Boost.Bind e Boost.Function che sono fantastici.

Esempio:

using boost::function
using boost::bind
using boost::signal

void some_other_func();    

Foo a;
Bar b;

signal<void()> sig;

sig.connect(bind(&Foo::foo,&a));
sig.connect(bind(&Bar::bar,&b));
sig.connect(some_other_func);

sig(); // calls -> a.foo(), b.bar(), some_other_func()

Supporta anche il blocco, la sofisticata gestione della connessione e altre cose accurate.

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