Я пытаюсь использовать таблицу виртуальных методов для вызова функций по индексу в
класс … Предположим, у нас есть следующий код:
class Base
{
public:
Base() {}
virtual ~Base() {}
virtual Base* call_func(unsigned int func_number)
{
// Some way to call f_n
}
protected:
virtual Base* f_1() const = 0;
virtual Base* f_2() const = 0;
virtual Base* f_3() const = 0;
};
Я уже реализовал это с помощью массивов функций, if-Statement
и case-Statement … Итак, есть ли лучший подход для вызова методов
используя только указатели (например, доступ к vtable) или что-то в этом роде?
Извините за мой ужасный английский: S … и спасибо заранее!
РЕДАКТИРОВАТЬ:
Спасибо за все предложения! Я собираюсь расширить свой вопрос:
После разрешения этого я собираюсь создать производные классы (например, производный 1 и производный 2)
с различными реализациями f_1, f_2, f_3 и имеют управление классом, как это:
class Control
{
protected:
Base* current;
public:
Control(Base* curr = new derived1): current(curr) {}
virtual ~Control()
{
delete current;
}
virtual void do_something(unsigned int func_numb)
{
delete current
Base* new = current->next_state(stl);
current = new;
}
};
Либо оператор переключения:
switch (func_number)
{
case 1:
f_1();
break;
case 2:
f_2();
break;
case 3:
f_3();
break;
}
Или используйте массив указателей на функции.
Нет переносимого способа доступа к таблице виртуальных функций; спецификация языка не определяет, как должна осуществляться виртуальная диспетчеризация, поэтому не требуется, чтобы таблица существовала, не говоря уже о том, чтобы она была доступна для программы.
Нет значительно лучшего способа сделать то, что вы хотите, чем упомянутые вами подходы: таблица указателей на функции или if
/switch
состояние.
Я полагаю, вы просто хотите найти все возможные способы ее решения.
Вы можете использовать карту (или вектор) указателей для функций-членов и инициализировать их один раз (в конструкторе или статически). Это может подражать Vtable.
Что-то между этими строками:
class Base
{
public:
Base() {
functions.insert(std::make_pair(1,&Base::f_1));
functions.insert(std::make_pair(2,&Base::f_2));
functions.insert(std::make_pair(3,&Base::f_3));
}
virtual ~Base() {}
virtual Base* call_func(unsigned int func_number)
{
return (this->*functions[func_number])();
}
protected:
std::map<unsigned int, Base*(Base:: *)()const> functions;
virtual Base* f_1() const = 0;
virtual Base* f_2() const = 0;
virtual Base* f_3() const = 0;
};
Это должно работать даже для унаследованных классов (я бы сделал call_func
не виртуальный, хотя).
И да, вы должны проверить, действительно ли элемент находится на карте (или в векторе), и если это не nullptr
,
Примечание 1: Безопаснее получить доступ к вашим методам, используя отображение методов или метод переключения, чем используя указатель vtable.
Примечание 2: Небольшая сборочная часть работает на VC ++, но не уверена для других компиляторов.
Хотя существует способ доступа к функциям виртуальной таблицы:
// create our object
X *obj = new X();
// access the vtable pointer
int* vptr = *(int**)obj;
// set the this pointer
__asm
{
mov ecx, obj
}
// call the first method from the vtable
( (void (*)()) vptr[0] )();
Смотрите для глубокого объяснения здесь:
http://kaisar-haque.blogspot.nl/2008/07/c-accessing-virtual-table.html