Может кто-нибудь дать мне представление об этой проблеме. Я искал в Интернете об этом, но не мог получить много информации, как я хотел.
Скажем, есть класс.
class Foo {
explicit Foo() {}
int getVar1();
int getVar2();
void setVar1(int v);
void setVar2(int v);
private:
int var1, var2;
};
Теперь, учитывая список токенов {«var1», «var2», … «varN»}, есть ли способ, которым я могу создать имя функции во время выполнения и вызвать эти функции-члены некоторого объекта типа Foo. как например
Foo obj;
string input = "Var1,Var2,Var3,...VarN";
vector<string> tokens = splitString(input);
for (vector<string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) {
string funName = "get" + *it;
// somehow call obj.getVar1()....obj.getVarN()
}
использование if else подходит для небольшого числа переменных, но не подходит для большого количества переменных. Использование связывания и функторов также не решает эту проблему. На одной веб-странице предлагалось сделать память исполняемой во время выполнения, а затем использовать reinterpret_cast, я не знаю, будет ли это работать.
ОБНОВИТЬ
Хорошо, из ответов и других поисков в Интернете я вижу, что в C ++ нет элегантного способа сделать это. На данный момент в C ++ нет отражения. Все взломы требуют разрешения времени компиляции указателей на функции-члены.
Может ли кто-нибудь дать мне идеи по проектированию альтернативных классов в этом сценарии, когда у вас много переменных, методов установки и методов получения … или есть ли методы получения и установки в C ++?
В качестве идеи рассмотрим следующий код
struct A
{
void f1() { std::cout << "A::f1()\n"; }
void f2() { std::cout << "A::f2()\n"; }
void f3() { std::cout << "A::f3()\n"; }
void f4() { std::cout << "A::f4()\n"; }
};
std::map<std::string, void( A::* )()> m = { { "f1", &A::f1 }, { "f2", &A::f2 }, { "f3", &A::f3 }, { "f4", &A::f4 } };
A a;
for ( auto p : m ) ( a.*p.second )();
Вы можете сделать карту как член данных вашего класса.
Вы не можете «добавлять» участников во время выполнения. C ++ строго типизирован во время компиляции.
Вы можете получить желаемое поведение, имея map<string, func_type>
и использовать его, чтобы преобразовать вашу строку в реальную функцию. Вы можете создать его, используя макросы, чтобы убедиться, что имена строк соответствуют именам функций.
#DEFINE ADD_METHOD(map_var, func) map_var["func"] = &func
Простое / не идеальное решение может заключаться в использовании промежуточных методов, проверяющих параметр и вызывающих метод getVar * соответственно.
Пример, подобный этому, может быть:
class Foo
{
public:
explicit Foo() {}
int getVar1() { return 1; }
int getVar2() { return 2; }
void setVar1(int v) { var1 = v; }
void setVar2(int v) { var2 = v; }
int callGetVar(const std::string &var)
{
if (var == "Var1") return getVar1();
if (var == "Var2") return getVar2();
else { return -1; }
}
private:
int var1, var2;
};
int main()
{
Foo obj;
std::string input = "Var1,Var2,Var3,...VarN";
std::vector<std::string> tokens = { "Var1", "Var2", "Var2", "Var1", "Var1", "Var2", "Var2", "Var1"};
auto tokensIT = tokens.begin();
for (; tokensIT != tokens.end(); ++tokensIT)
{
// somehow call obj.getVar1()....obj.getVarN()
std::cout << obj.callGetVar(*tokensIT);
}
return 0;
}
почему бы не посмотреть на это референтным способом:
Для каждой переменной присваивают порядковый номер, начиная с 0, 1, 2 ….
Вы сохраняете эти значения на карте (ключ — это имя переменной, значение — это назначенное значение).
Все значения этих переменных вы храните в массиве, так что значение первой переменной в ячейке 0, следующей — в ячейке 1 и т. Д.
поэтому, когда вы хотите получить / установить значение, все, что вам нужно сделать, это найти его индекс на карте и получить доступ к соответствующей ячейке в векторе.