Я прочитал эту статью и понял, что когда вы хотите вызвать указатель на функцию-член, вам понадобится экземпляр (либо указатель на него, либо ссылка на стек) и назовите его так:
(instance.*mem_func_ptr)(..)
or
(instance->*mem_func_ptr)(..)
Мой вопрос основан на следующем: поскольку у вас есть экземпляр, почему бы не вызвать функцию-член напрямую, например:
instance.mem_func(..) //or: instance->mem_func(..)
Каково рациональное / практическое использование указателей на функции-члены?
[редактировать]
Я играю с X-development и дошел до стадии, когда я реализую виджеты; поток цикла событий для перевода X-событий в мои классы и виджеты должен запускать потоки для каждого виджета / окна, когда для них прибывает событие; чтобы сделать это правильно, я подумал, что мне нужны указатели на функции для обработчиков событий в моих классах.
Не совсем так: я обнаружил, что могу сделать то же самое более ясным и аккуратным способом, просто используя виртуальный базовый класс. Нет необходимости в указателях на функции-члены. Именно при разработке вышеизложенного возникло сомнение в практическом использовании / значении указателей на функции-члены.
Тот простой факт, что вам нужна ссылка на экземпляр для использования указателя на функцию-член, устраняет необходимость в нем.
[edit - @sbi и другие]
Вот пример программы, чтобы проиллюстрировать мою точку зрения: (обратите внимание на Handle_THREE ())
#include <iostream>
#include <string>
#include <map>
//-----------------------------------------------------------------------------
class Base
{
public:
~Base() {}
virtual void Handler(std::string sItem) = 0;
};
//-----------------------------------------------------------------------------
typedef void (Base::*memfunc)(std::string);
//-----------------------------------------------------------------------------
class Paper : public Base
{
public:
Paper() {}
~Paper() {}
virtual void Handler(std::string sItem) { std::cout << "Handling paper\n"; }
};
//-----------------------------------------------------------------------------
class Wood : public Base
{
public:
Wood() {}
~Wood() {}
virtual void Handler(std::string sItem) { std::cout << "Handling wood\n"; }
};
//-----------------------------------------------------------------------------
class Glass : public Base
{
public:
Glass() {}
~Glass() {}
virtual void Handler(std::string sItem) { std::cout << "Handling glass\n"; }
};
//-----------------------------------------------------------------------------
std::map< std::string, memfunc > handlers;
void AddHandler(std::string sItem, memfunc f) { handlers[sItem] = f; }
//-----------------------------------------------------------------------------
std::map< Base*, memfunc > available_ONE;
void AddAvailable_ONE(Base *p, memfunc f) { available_ONE[p] = f; }
//-----------------------------------------------------------------------------
std::map< std::string, Base* > available_TWO;
void AddAvailable_TWO(std::string sItem, Base *p) { available_TWO[sItem] = p; }
//-----------------------------------------------------------------------------
void Handle_ONE(std::string sItem)
{
memfunc f = handlers[sItem];
if (f)
{
std::map< Base*, memfunc >::iterator it;
Base *inst = NULL;
for (it=available_ONE.begin(); ((it != available_ONE.end()) && (inst==NULL)); it++)
{
if (it->second == f) inst = it->first;
}
if (inst) (inst->*f)(sItem);
else std::cout << "No instance of handler for: " << sItem << "\n";
}
else std::cout << "No handler for: " << sItem << "\n";
}
//-----------------------------------------------------------------------------
void Handle_TWO(std::string sItem)
{
memfunc f = handlers[sItem];
if (f)
{
Base *inst = available_TWO[sItem];
if (inst) (inst->*f)(sItem);
else std::cout << "No instance of handler for: " << sItem << "\n";
}
else std::cout << "No handler for: " << sItem << "\n";
}
//-----------------------------------------------------------------------------
void Handle_THREE(std::string sItem)
{
Base *inst = available_TWO[sItem];
if (inst) inst->Handler(sItem);
else std::cout << "No handler for: " << sItem << "\n";
}
//-----------------------------------------------------------------------------
int main()
{
Paper p;
Wood w;
Glass g;
AddHandler("Paper", (memfunc)(&Paper::Handler));
AddHandler("Wood", (memfunc)(&Wood::Handler));
AddHandler("Glass", (memfunc)(&Glass::Handler));
AddAvailable_ONE(&p, (memfunc)(&Paper::Handler));
AddAvailable_ONE(&g, (memfunc)(&Glass::Handler));
AddAvailable_TWO("Paper", &p);
AddAvailable_TWO("Glass", &g);
std::cout << "\nONE: (bug due to member-function address being relative to instance address)\n";
Handle_ONE("Paper");
Handle_ONE("Wood");
Handle_ONE("Glass");
Handle_ONE("Iron");
std::cout << "\nTWO:\n";
Handle_TWO("Paper");
Handle_TWO("Wood");
Handle_TWO("Glass");
Handle_TWO("Iron");
std::cout << "\nTHREE:\n";
Handle_THREE("Paper");
Handle_THREE("Wood");
Handle_THREE("Glass");
Handle_THREE("Iron");
}
{edit] Возможная проблема с прямым вызовом в приведенном выше примере:
В Handler_THREE () имя метода должно быть жестко закодировано, чтобы изменения вносились везде, где он используется, применить какие-либо изменения к методу. При использовании указателя на функцию-член единственное дополнительное изменение, которое необходимо сделать, - это место создания указателя.
[править] Практическое использование, почерпнутое из ответов:
Из ответ Chubsdad:
Что: для вызова mem-func-ptr используется специальная функция« Caller »;
Преимущество: для защиты кода с помощью функций, предоставляемых другими объектами.
Как: если определенные функции используются во многих местах и имя и / или параметры меняются, вам нужно только измените имя, в котором он размещен как указатель, и адаптируйте вызов в функции «Caller». (Если функция используется как instance.function (), ее нужно везде менять.)
Из ответ Мэтью Флашена:
Что: локальная специализация в классе
Преимущество: делает код более ясным, простым и легким в использовании и обслуживании
Как: заменяет код, который обычно реализуется с использованием сложной логики, на ( потенциально) большие операторы switch () / if-then с прямыми указателями на специализацию; довольно похожа на функцию "Caller" выше.
mem_func
не обязательно статичен, поэтому мы используемmem_func_ptr
. Тот факт, что вам нужен экземпляр, не имеет ничего общего с указателями на функции или их использованием. Вы ни в чем не сбиваетесь с пути. Если вы понимаете, для чего нужны указатели на обычные функции, вы понимаете, для чего нужны указатели на функции-члены. Точно то же самое. Итак: вы понимаете, для чего нужны обычные указатели на функции? - person GManNickG   schedule 18.10.2010a.*b(c)
этоa.*(b(c))
, не то, что вы имели в виду:(a.*b)(c)
. Аналогично->*
. - person   schedule 19.10.2010