Хранение и выполнение функций из класса (C ++) - PullRequest
3 голосов
/ 13 ноября 2011

У меня есть класс под названием «Задачи», который должен хранить методы из других классов и иметь возможность их выполнять.Я хотел бы, чтобы это работало так:

Window *window = new Window();
Tasks* tasks = new Tasks();
tasks.m_tasks.Add(window.Create("My Window"));

Тогда я мог бы вызвать создание этого окна из своего класса задач, перебирая сохраненные задачи и выполняя каждое из них:

tasks.ExecuteTasks();

Какова будет структура данных m_tasks, в которой хранятся функции, и как я могу их вызвать?

Ответы [ 5 ]

4 голосов
/ 13 ноября 2011

Я бы использовал std::list<std::function<void()> > или boost::function, если std::function недоступен.

И вам нужно будет изменить синтаксис этого вызова Add, чтобы избежать выполнения Create метод сразу.

C ++ 11:

class Tasks {
public:
    void Add(const std::function<void()>& f)
    { callbacks_.push_back( f ); }

    void Add(std::function<void()>&& f)
    { callbacks_.emplace_back( std::move( f ) ); }
    // ...
private:
    std::list<std::function<void()> > callbacks_;
};

int main() {
    Window window;
    // ...
    tasks.Add( [&]() { window.Create("My Window"); } );
    // ...
}

C ++ 03:

class Tasks {
public:
    void Add(const boost::function<void()>& f)
    { callbacks_.push_back( f ); }

private:
    std::list<boost::function<void()> > callbacks_;
};

int main() {
    // ...
    tasks.Add( boost::bind( &Window::Create, boost::ref(window), "My Window" ) );
    // ...
}
1 голос
/ 13 ноября 2011

Вы можете использовать список tr1 или boost :: functions, как говорит @aschepler, но этот сценарий идеально подходит для boost :: сигналов .

class Tasks {
    boost::signal<void ()> m_tasks;
};

// ...
tasks.m_tasks.connect(&someFunction);

// ExecuteTasks:
tasks.m_tasks();

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

0 голосов
/ 13 ноября 2011

Это относительно просто, если вы знаете, каковы будут аргументы. Вы можете использовать указатель на функцию с некоторыми дополнениями, чтобы сделать его указателем на метод. См:

http://mdzahidh.wordpress.com/2008/07/16/pointer-to-c-class-methods-or-should-you-call-em-method-pointers/

Однако это не позволит вам передавать произвольные аргументы. Вы могли бы сделать это с помощью шаблонов C ++, но это было бы неприятно. Я настоятельно рекомендую избегать этого и использовать традиционные указатели функций / методов, если это возможно.

0 голосов
/ 13 ноября 2011

m_tasks будет какой-то коллекцией, я бы, вероятно, использовал список, если вам не нужно будет добавлять / удалять посередине.В списке вы будете хранить указатель на функцию.То есть указатель на функцию.С простой версией кода, который я имею ниже, вы не можете иметь универсальные указатели функций, вы должны быть конкретны в отношении типов параметров и типа возвращаемого значения.Может быть возможно использовать шаблоны, чтобы нарушить это ограничение.Я не знаю по макушке.

// define FunctionPtr as a pointer to a function that takes a single char* param and returns void 
typedef void(*FunctionPtr)(char*);
// define an stl:list of FunctionPtr items
std:list<FunctionPtr> m_tasks;
0 голосов
/ 13 ноября 2011

Для этого вам понадобится немного сложная структура:

class Task
{
public:
   virtual void Execute()=0;
};
template<class T, class R, class P1>
class Function1 : public Task
{
public:
   Function1(T *ptr, R (T::*fptr)(P1), P1 p1) : ptr(ptr), fptr(fptr),p1(p1) { }
   void Execute() { (ptr->*fptr)(p1); }
private:
   T *ptr;
   R (T::*fptr)(P1);
   P1 p1;
};
std::vector<Task*> vec;
...