список/вектор методов класса в переменной класса

Мне нужно вести список методов, которые будут выполняться в разном порядке для тестирования. Мы переходим с C на C++, чтобы использовать фреймворк Google. Можно ли поддерживать список указателей функций на некоторые методы класса, которые будут использоваться для выполнения внутри класса, чтобы их можно было использовать после создания экземпляра? см. http://cpp.sh/265y

#include <iostream>
#include <string>
#include <vector>
using namespace std;

typedef void (*funcType)();

class Sample {
    public:
    vector<funcType> func_list;

    Sample();

    void formList();
    void method1();
    void method2();
    void method3();    
};

void Sample::formList() {
    func_list.push_back(&method1);
    func_list.push_back(&method2);
    func_list.push_back(&method3);
}

void Sample::method1 () {
    cout << "method1" << endl;
}

void Sample::method2 () {
    cout << "method2" << endl;
}

void Sample::method3 () {
    cout << "method3" << endl;
}

int main()
{
    Sample sample; //* = new Sample();
    sample.formList();
    vector<funcType>::iterator it;
    for (it = sample.func_list.begin(); it != sample.func_list.end(); ++it) {
         ((*it));
    }

}

Ответ: http://cpp.sh/8rr2


person bicepjai    schedule 14.10.2015    source источник


Ответы (2)


Вы можете использовать ужасный синтаксис указателя на функцию-член:

Жить на Coliru

// Example program
#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Sample;

typedef void (Sample::*funcType)();

class Sample {
  public:
    vector<funcType> func_list;

    Sample(){}

    void formList();
    void method1();
    void method2();
    void method3();
};

void Sample::formList() {
    func_list.push_back(&Sample::method1);
    func_list.push_back(&Sample::method2);
    func_list.push_back(&Sample::method3);
}

void Sample::method1() { cout << "method1" << endl; }

void Sample::method2() { cout << "method2" << endl; }

void Sample::method3() { cout << "method3" << endl; }

int main() {
    Sample sample; //* = new Sample();
    sample.formList();
    vector<funcType>::iterator it;
    for (it = sample.func_list.begin(); it != sample.func_list.end(); ++it) {
        (sample.*(*it))(); // HORRIFIC, INNIT? SEE BELOW FOR BETTER
    }
}

НАМНОГО ЛУЧШЕ:

Однако вы могли бы быть более универсальными, используя C++11/TR1 std::function<> или boost::function<>:

typedef function<void(Sample*)> funcType;

// ...
func_list.push_back(mem_fn(&Sample::method1));
func_list.push_back(mem_fn(&Sample::method2));
func_list.push_back(mem_fn(&Sample::method3));

Смотрите Прямой эфир на Coliru слишком

for (it = sample.func_list.begin(); it != sample.func_list.end(); ++it) {
    (*it)(&sample); // much better
}

Дополнительная универсальность в основном заключается в том, что вы можете обслуживать различные подписи:

class Sample {
  public:
    vector<funcType> func_list;

    Sample(){}

    void formList();
    void method1(int);
    void method2(std::string);
    void method3(double, double, double);
};

void Sample::formList() {
    using std::placeholders::_1;
    func_list.push_back(bind(&Sample::method1, _1, 42));
    func_list.push_back(bind(&Sample::method2, _1, "Hello world"));
    func_list.push_back(bind(&Sample::method3, _1, 1, 2, 3));
}
person sehe    schedule 14.10.2015
comment
Так много обещаний :) - person sehe; 15.10.2015
comment
Надеюсь, вы читали о std::function<> — он даже позволит вам смешивать методы, вызываемые для разных объектов (просто используйте std::function<void()> и привяжите все или используйте захват лямбда-выражений). Я включил соответствующий код из связанной живой демонстрации. - person sehe; 15.10.2015
comment
Я подождал, а затем пошел дальше! я приму ваш, он выглядит лучше - person bicepjai; 15.10.2015

Вступление

В настоящее время вы объявили funcType как псевдоним для void(*)(), который является указателем на некоторую функцию, которая не принимает аргументов и возвращает void. Вам следует использовать указатель на функцию-член, поскольку она будет соответствовать сущностям, которые вы пытаетесь вызвать.

class Sample;
typedef void (Sample::*funcType)(); 

Вам также нужно будет квалифицировать свои функции-члены, когда вы хотите получить их адрес:

void Sample::formList() {
    func_list.push_back(&Sample::method1);
    func_list.push_back(&Sample::method2);
    func_list.push_back(&Sample::method3);
}

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

for (it = sample.func_list.begin(); it != sample.func_list.end(); ++it) {
     (sample.*(*it)) (); // invoke the member-function referred to by `it`
}                        // on the object named `sample`

Дополнительная литература



Пример реализации

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Sample;
typedef void (Sample::*funcType)();

class Sample {
  public:
    vector<funcType> func_list;

    void formList();
    void method1();
    void method2();
    void method3();    
};

void Sample::formList() {
  func_list.push_back(&Sample::method1);
  func_list.push_back(&Sample::method2);
  func_list.push_back(&Sample::method3);
}

void Sample::method1 () {
  cout << "method1" << endl;
}

void Sample::method2 () {
  cout << "method2" << endl;
}

void Sample::method3 () {
  cout << "method3" << endl;
}

int main()
{
  Sample sample; //* = new Sample();
  sample.formList();
  vector<funcType>::iterator it;
  for (it = sample.func_list.begin(); it != sample.func_list.end(); ++it) {
    (sample.*(*it)) ();
  }
}
method1
method2
method3
person Filip Roséen - refp    schedule 14.10.2015