Pergunta

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

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

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

O método addFunction adiciona a função de uma lista na classe base,
que pode então ser enumerados para chamar todas as funções.

Existe alguma maneira de simplificar (menos trabalho digitação) a adição de funções?

Foi útil?

Solução

Parece que você atribuir um ponteiro função de membro para uma função da classe derivada para um ponteiro função de membro para uma função da classe base. Bem, isso é proibido, porque abre um buraco no sistema-tipo. Ele vem em uma surpresa (pelo menos para mim, a primeira vez que ouvi isso). Leia este resposta para porque.

Para responder a sua pergunta real - eu faria addFunction um modelo:

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

Alterar addFunction na base de classe para isso:

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

Melhor utilização static_cast, porque ele vai dizer se Derived não é realmente derivado FunctionSet.

Outras dicas

Você pode explicar o que você está tentando alcançar, fazendo isso?

Este parece ser um design bastante ruim, você não pode ter uma classe abstrata ( "c ++ interface de") como "computável" que tem um function1 virtual pura, subclasse Computable para cada aplicação, e depois ter MyFunctionSet manter um conjunto de Computable?

Existe uma razão específica que você está usando ponteiros de função?

Então, eu tendem a discordar de Uri, um pouco.

Se você está implementando o padrão Observer, o que você quer é ser capaz de dizer:

"Quando objeto X faz Y, eu quero executar código Z".

Indo com uma abordagem puramente baseado em uma classe abstrata não é a melhor maneira de fazer isso. Exigindo uma classe separada (especialmente em C ++) para cada manipulador de eventos é um exagero. Se você vem de Java, que é como eles fazem tudo. No entanto Java tem 2 características que torna esta apenas ligeiramente irritante: classe anônima, e "instância" aulas membros. Isso permite que você defina vários manipuladores para vários eventos da mesma classe. Você tem que prefixar os métodos com "class {", mas você pode fazê-lo.

não

C ++ não tem aulas tanto anónimos ou "instância" aulas membros. Isso faz usando uma classe abstrata para eventos muito mais complicado se você tem vários manipuladores que precisam estado share. Você tem que fazer o equivalente a geração de fechamento à mão, que pode ficar muito irritante muito rapidamente.

.NET usa delegados para manipulação de eventos, que são basicamente digita ponteiros de função de segurança. Eles fazem o código para lidar com eventos muito para a frente. Ao contrário dos ponteiros de função em C ++, no entanto, um unifica delegado membro ponteiros de função e ponteiros função estática. Basicamente ele pode caril o "presente" parâmetro de qualquer função de membro, deixando uma função ponteiros que se parece com um ponteiro de função estática. Isto significa que o tipo do objeto manipulando o evento não faz parte da "interface" do evento. Isso faz com que seja muito flexível.

Você não pode fazer isso usando diretamente C ++ ponteiros de função membro porque os "este" tipo acaba sendo uma parte do tipo de ponteiro de função, assim, limitar seus manipuladores apenas aparecendo dentro da classe atual.

A melhor solução para C ++ é um híbrido entre as duas. O que você quer é uma interface genérica como esta:

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

E, em seguida, uma implementação para funções de membro como este

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);
}

Você também pode definir uma classe semelhante manipulador para métodos estáticos. Então você pode apenas fazer coisas como esta:

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

Você poderia sobrecarregar o operador de adição, eu suponho.

Se você está tentando fazer um sistema de retorno de chamada ou algo que eu recomendaria a biblioteca Boost.Signals. Basicamente, ele agrega funções e chama o grupo de funções no comando (como qualquer outra biblioteca de sinal), mas também é projetado para trabalhar com Boost.Bind e Boost.Function que são impressionantes.

Exemplo:

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()

também suporta o bloqueio, sofisticado gerenciamento de conexão e outras coisas legais.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top