我已经阅读了这篇文章,我从中得到的是,当你想调用一个指向成员函数的指针时,你需要一个实例(指向一个或堆栈引用的指针)并这样调用它:
(instance.*mem_func_ptr)(..)
or
(instance->*mem_func_ptr)(..)
我的问题是基于这个:既然你有实例,为什么不直接调用成员函数,像这样:
instance.mem_func(..) //or: instance->mem_func(..)
指向成员函数的指针的合理/实际用途是什么?
[编辑]
我正在玩 X-development 并达到了我正在实现小部件的阶段;当事件到达时,用于将 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() 中,方法的名称必须是硬编码的,强制在使用它的任何地方进行更改,以将任何更改应用于方法。使用指向成员函数的指针唯一要做的额外更改是创建指针的位置。
[编辑]从答案中收集到的实际用途:来自 Chubsdad 的回答
:什么:
专用的“调用者”函数用于调用 mem-func-ptr;
好处:使用其他对象提供的函数来保护代码
如何:如果特定函数在许多地方使用并且名称和/或参数发生变化,那么您只需将其分配的名称更改为指针,并在“调用者”函数中调整调用。(如果该函数用作 instance.function() 则必须在任何地方进行更改。)
来自Matthew Flaschen 的回答:
什么:类中的局部特
化 好处:使代码更清晰、更简单、更易于使用和维护
如何:用(可能)大型 switch()/if 替换通常使用复杂逻辑实现的代码-then 直接指向特化的语句;与上面的“调用者”功能非常相似。