Нужен способ сохранить функции в списке, а затем вызвать их - PullRequest
3 голосов
/ 23 сентября 2011

Этот список должен содержать функции, они могут быть из разных пространств имен и даже методов экземпляров классов.
Затем этот список будет повторяться и вызываться все функции и методы.Было бы хорошо, если бы они могли также содержать аргументы.

Я думал об использовании std :: vector, но я подозреваю, что я не совсем прав в этом предположении.

Какой подход вы мне порекомендуете?Любая помощь приветствуется.

Ответы [ 3 ]

4 голосов
/ 23 сентября 2011

Вы можете использовать std :: function и std :: bind, если ваш компилятор уже поддерживает это.

#include <functional>
#include <vector>

void x(int) {}
void y() {}
class Z {
public:
    void z() {}
};

int main(int argc, char *argv[])
{
    typedef std::function<void ()> VoidFunc;
    typedef std::vector<VoidFunc> FuncVector;
    FuncVector functions;

    functions.push_back(std::bind(&x, 1));
    functions.push_back(&y);
    Z z1;
    functions.push_back(std::bind(&Z::z, z1));

    for(FuncVector::iterator i = functions.begin(); i != functions.end(); i++) {
        (*i)();
    }

    return 0;
}
2 голосов
/ 23 сентября 2011

Пусть все ваши функции реализуют шаблон команды .

Ваш список становится

std::list<Command>

Когда вы перебираете список, вы вызываете Execute () метод каждого элемента списка.

Например, скажем, у вас есть простой командный интерфейс с именем Commander:

class Commander
{
public:
    virtual        ~Commander;

    virtual void    Execute();//= 0;
};

И у вас есть три объекта, которые вы хотите поместить в свой список: AБорзая, Gyrefalcon и Подруга.Оберните каждый в объект Commander, который вызывает интересующую функцию объекта.Борзая бежит:

class RunGreyhound: public Commander
{
public:
    void            Execute()
                    {
                        mGreyhound->Run();
                    }
private:
    Greyhound*      mGreyhound;
};

Жирный сокол летит:

class RunGyrefalcon: public Commander
{
public:
    void            Execute()
                    {
                        mGyrefalcon->Fly( mGyrefalcon->Prey() );
                    }    
private:
    Gyrefalcon*      mGyrefalcon;
};

И Подруга кричит:

class RunGirlfriend: public Commander
{
public:
    void            Execute()
                    {
                        mGirlfriend->Squawk( mGirlfriend->MyJunk(), mGirlfriend->Mytrun() );
                    }
private:
    Girlfriend*     mGirlfriend;
};

Заполните объекты Командующего в вашем списке.Теперь вы можете перебирать их и вызывать метод Execute () каждого элемента:

std::list<Commander> cmdlist;

RunGreyhound dog;
cmdlist.push_back( dog );

RunGyrefalcon bird;
cmdlist.push_back( bird );

RunGirlfriend gurl;
cmdlist.push_back( gurl );

for ( std::list<Commander>::iterator rit = cmdlist.begin(); rit != cmdlist.end(); ++rit )
{
    rit->Execute();
}
2 голосов
/ 23 сентября 2011

Если вы не хотите использовать существующее решение, такое как boost :: function, вам нужно будет создать базовый класс, представляющий функцию, а затем производные классы, которые обертывают различные источники функций. Например:

#include <iostream>
#include <list>
using std::cout;
using std::list;

struct Function {
  virtual ~Function() { }
  virtual void operator()() = 0;
};

struct PlainFunction : Function {
  PlainFunction(void (*function_ptr_arg)()) : function_ptr(function_ptr_arg) { }
  virtual void operator()() { (*function_ptr)(); }
  void (*function_ptr)();
};

template <typename T> 
struct MethodFunction : Function {
  MethodFunction(T &obj_arg,void (T::*method_ptr_arg)())
    : obj(obj_arg), method_ptr(method_ptr_arg)
  {
  }
  virtual void operator()() { (obj.*method_ptr)(); }
  T &obj;
  void (T::*method_ptr)();
};

void f()
{
  cout << "Called f()\n";
}

struct A {
  void f() { cout << "Called A::f()\n"; }
};

int main(int argc,char **argv)
{
  list<Function *> functions;
  functions.push_back(new PlainFunction(f));
  A a;
  functions.push_back(new MethodFunction<A>(a,&A::f));
  list<Function *>::iterator i = functions.begin();
  for (;i!=functions.end();++i) {
    (*(*i))();
  }
  while (!functions.empty()) {
    Function *last_ptr = functions.back();
    functions.pop_back();
    delete last_ptr;
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...