Страницы

Поиск по вопросам

вторник, 8 января 2019 г.

Как выделить память для массива функций

class name { public: name(int); double(*act)(double);
double f1(double); double f2(double); double f3(double); };
name::name(int i) { this->act = new (double[i](double)); }
error: creating array of functions
Вот так ругается компилятор. Как можно реализовать такой динамический массив?


Ответ

Если говорить про обычные функции:
int foo1(float) { return 1; }
int foo2(float) { return 2; }
int foo3(float) { return 3; }
int main() { // в типе должна быть описана сигнатура необходимой функции using fun_type = int(*)(float); // int - возвращаемый тип // float - аргумент, (*) - означает что мы хотим создать указатель на функцию
// создали массив указателей на функции // поместили адреса фукций foo1, foo2, foo3 fun_type funs[] = { &foo1, &foo2, &foo3 };
// вызываем функцию (в данном случае foo1) int result = funs[0](10.0f);
return 0; }
Однако в вашем случае необходимы не просто указатели на функцию, а указатели на методы класса. Это другие сущности и, настолько они особенны, что даже не поддаются void*. Но такая проблема также решается:
class widget { public: // имеется несколько методов с одинаковой сигнатурой void foo1(int);
void foo2(int);
void foo3(int);
// внимание на модификатор const // объяснения ниже void foo4_c(int) const; };
int main() {
// объявление массива указателей на метод класса widget // как и в случае с обычным указателем, этот указатель // просто локальная переменная // эти указатели не относятся к какому-нибудь конкретному объекту // они относятся к классу widget в целом void(widget::*fun_ptr[3])(int);
// устанавливаем несколько конкретных значений // можно было при объявлении инициализировать списком {} fun_ptr[0] = &widget::foo1; fun_ptr[1] = &widget::foo2; fun_ptr[2] = &widget::foo3;
// по поводу const в объявлении метода: // const является часть сигнатуры метода! // поэтому следующий код не скомпилируется // по причине разных типов указателей // fun_ptr[2] = &widget::foo4_c; // error!
// для const-методов необходимо указать спецификатор const void(widget::*const_fun_ptr)(int) const;
const_fun_ptr = &widget::foo4_c; // ok!
// создается конкретный объект класса widget obj;
// и указатель на динамически распределенный объект widget *ptr_to_obj = new widget();
// собственно использование указателей // obj.* - обращение к члену указателю // т.к. fun_ptr массив мы указываем еще индекс // по которому находится нужный метод // необходимо взять в скобки (obj.*fun_ptr[0])(10);
// для указателей на объекты используется // чуть-чуть другой синтаксис (ptr_to_obj->*fun_ptr[0])(10);
delete ptr_to_obj; return 0; }
Создать динамический массив указателей на обычную функцию не слишком сложно.
using fptr = void(*)(int); fptr* fptrs = new fptr[10]; delete[] fptrs;
Чуть сложнее дело обстоит с указателями на методы. У меня получилось достичь необходимого результата следующим образом:
#include
class widget { public: void foo1(int) { std::cout << "foo1
"; }
void foo2(int) { std::cout << "foo2
"; }
void foo3(int) { std::cout << "foo3
"; } };
int main() { void(widget::*fptr)(int);
using fptr_type = decltype(fptr);
fptr_type* fptrs = new fptr_type[3];
fptrs[0] = &widget::foo1; fptrs[1] = &widget::foo2; fptrs[2] = &widget::foo3;
widget a;
(a.*fptrs[0])(10); (a.*fptrs[1])(10); (a.*fptrs[2])(10);
delete[] fptrs;
std::cin.get(); return 0; }

Комментариев нет:

Отправить комментарий