我已阅读了这篇文章,我的理解是当你想调用一个成员函数指针时,你需要一个实例(可以是指向实例的指针或堆栈引用),并进行如下调用:
(instance.*mem_func_ptr)(..)
or
(instance->*mem_func_ptr)(..)
我的问题基于此:既然您有该实例,为什么不直接调用成员函数,像这样:
instance.mem_func(..) //or: instance->mem_func(..)
指向成员函数的指针在实际中有什么合理/实用的用途?[编辑]
我正在进行X开发,并到达了实现小部件的阶段;将X事件转换为我的类和小部件的事件循环线程需要在它们到达时为每个小部件/窗口启动线程;为了正确地执行此操作,我认为需要使用类中事件处理程序的函数指针。
事实并非如此:我发现可以通过简单地使用虚基类以更加清晰、整洁的方式完成同样的工作。没有任何必要使用成员函数指针。正是在开发上述内容时,对指向成员函数的指针的实际可用性/含义产生了疑问。
简单事实是,您需要引用一个实例才能使用成员函数指针,这使得其变得过时。
[编辑-@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()中,方法名必须被硬编码,这意味着任何地方使用该方法都必须进行更改才能应用任何更改。使用成员函数指针,唯一需要进行的额外更改是创建指针的位置。
[edit] 从答案中获得的实际用途:
来自Chubsdad的答案:
什么: 使用专门的'Caller'函数来调用mem-func-ptr;
好处: 保护使用其他对象提供的功能的代码
如何: 如果特定的函数在许多地方使用且名称和/或参数发生变化,则只需更改分配指针的位置的名称,并在'Caller'-function中适应调用即可。(如果函数被用作instance.function(),则必须在所有地方进行更改。)
来自Matthew Flaschen的答案:
什么: 类中的本地特化
好处: 使代码非常清晰,简单易用且易于维护
如何: 使用直接指向特化的指针替换通常使用复杂逻辑实现的代码,这些代码具有(潜在)大型开关()/if-then语句,与上述'Caller'-function非常相似。
mem_func
不一定是静态的,因此我们使用mem_func_ptr
。你需要一个实例与函数指针或它们的使用无关。你正在为无关紧要的事情分心。如果你理解“普通”函数指针的用途,那么你就理解了成员函数指针的用途,完全相同。所以,你理解普通函数指针的用途吗? - GManNickG