C++ 指向成员函数的指针的实际用途是什么?
我已经通读了,我从中得到的是,当您想要调用一个指向成员函数的指针时,您需要一个实例(指向一个成员函数的指针或堆栈引用),并这样调用它:C++ 指向成员函数的指针的实际用途是什么?,c++,member-functions,C++,Member Functions,我已经通读了,我从中得到的是,当您想要调用一个指向成员函数的指针时,您需要一个实例(指向一个成员函数的指针或堆栈引用),并这样调用它: (instance.*mem_func_ptr)(..) or (instance->*mem_func_ptr)(..) 我的问题是基于这样的:既然您有实例,为什么不直接调用成员函数,如下所示: instance.mem_func(..) //or: instance->mem_func(..) 指向成员函数的指针的合理/实际用途是什么 [编辑
(instance.*mem_func_ptr)(..)
or
(instance->*mem_func_ptr)(..)
我的问题是基于这样的:既然您有实例,为什么不直接调用成员函数,如下所示:
instance.mem_func(..) //or: instance->mem_func(..)
指向成员函数的指针的合理/实际用途是什么
[编辑]
我正在玩X-development&达到了实现widget的阶段;用于将X事件转换为我的类和小部件的事件循环线程需要在每个小部件/窗口的事件到达时启动线程;为了正确地执行此操作,我认为我需要指向类中事件处理程序的函数指针
事实并非如此:我确实发现,通过简单地使用虚拟基类,我可以以更清晰、更整洁的方式做同样的事情。不需要任何指向成员函数的指针。正是在发展上述内容的同时,人们对成员函数指针的实用性/意义产生了怀疑
为了使用成员函数指针,您需要引用一个实例,这一简单的事实使您不再需要引用一个实例
[编辑-@sbi和其他]
下面是一个示例程序来说明我的观点:
(请特别注意“Handle_THREE()”)
#包括
#包括
#包括
//-----------------------------------------------------------------------------
阶级基础
{
公众:
~Base(){}
虚拟空处理程序(std::string sItem)=0;
};
//-----------------------------------------------------------------------------
typedef void(基::*memfunc)(标准::字符串);
//-----------------------------------------------------------------------------
课堂论文:公共基础
{
公众:
纸张(){}
~Paper(){}
虚拟void处理程序(std::string sItem){std::cout-available\u-TWO;
void AddAvailable_TWO(std::string sItem,Base*p){available_TWO[sItem]=p;}
//-----------------------------------------------------------------------------
无效句柄(std::string sItem)
{
memfunc f=handlers[sItem];
如果(f)
{
std::map ::迭代器;
Base*inst=NULL;
对于(it=available_ONE.begin();((it!=available_ONE.end())&&(inst==NULL));it++)
{
如果(it->second==f)inst=it->first;
}
if(仪表)(仪表->*f)(现场);
else std::cout使用任何函数指针的原因相同:在调用函数指针变量之前,您可以使用任意程序逻辑来设置它。您可以使用一个开关,一个if/else,将它传递到函数中
编辑:
问题中的示例确实表明,有时可以使用虚拟函数作为指向成员函数的指针的替代方法。这并不奇怪,因为编程中通常有多种方法
下面是一个虚拟函数可能没有意义的示例。与OP中的代码一样,这是为了说明问题,而不是为了特别现实。它显示了一个带有公共测试函数的类。这些函数使用内部、私有函数。内部函数只能在安装后调用,并且必须在安装后调用埃尔沃兹
#include <iostream>
class MemberDemo;
typedef void (MemberDemo::*MemberDemoPtr)();
class MemberDemo
{
public:
void test1();
void test2();
private:
void test1_internal();
void test2_internal();
void do_with_setup_teardown(MemberDemoPtr p);
};
void MemberDemo::test1()
{
do_with_setup_teardown(&MemberDemo::test1_internal);
}
void MemberDemo::test2()
{
do_with_setup_teardown(&MemberDemo::test2_internal);
}
void MemberDemo::test1_internal()
{
std::cout << "Test1" << std::endl;
}
void MemberDemo::test2_internal()
{
std::cout << "Test2" << std::endl;
}
void MemberDemo::do_with_setup_teardown(MemberDemoPtr mem_ptr)
{
std::cout << "Setup" << std::endl;
(this->*mem_ptr)();
std::cout << "Teardown" << std::endl;
}
int main()
{
MemberDemo m;
m.test1();
m.test2();
}
#包括
班级成员演示;
typedef void(MemberDemo::*MemberDemoPtr)();
类成员演示
{
公众:
void test1();
void test2();
私人:
void test1_internal();
void test2_internal();
使用“设置”或“拆卸”无效(MemberDemoPtr p);
};
void MemberDemo::test1()
{
使用安装程序进行拆卸(&MemberDemo::test1\u internal);
}
void MemberDemo::test2()
{
使用安装程序进行拆卸(&MemberDemo::test2\u internal);
}
void MemberDemo::test1_internal()
{
用例是您有多个具有相同签名的成员方法,并且您希望构建在给定情况下应该调用哪个方法的逻辑。这有助于实现状态机算法
不是你每天都用的东西…有很多实际用途。我想到的一个用途如下:
假设核心功能如下(适当定义的myfoo和MFN)
这样一个函数在存在指向成员函数的指针的情况下,为扩展而打开,为修改而关闭()
另请参阅smartly使用指向成员的指针的函数。想象一下,您有一个函数可以根据传递的参数调用几个不同函数中的一个
您可以使用一个巨大的if/else if语句
您可以使用switch语句
或者可以使用函数指针表(跳转表)
如果你有很多不同的选择,跳转表可以是一个更干净的方式来安排你的代码
不过,这取决于个人偏好。Switch语句和跳转表或多或少都对应于相同的编译代码:)
我的问题基于此:既然您有实例,为什么不直接调用成员函数[?]
前面:在C++编程的15多年里,我使用成员指针可能是两次或三次。虚拟函数在周围,没有什么太多的用途。
如果要对一个对象(或多个对象)调用某个成员函数,并且必须先决定调用哪个成员函数,然后才能找到哪个对象,则可以使用它们在上调用它就是有人想这样做的一个例子。我发现,当您查看更高级别的构造(如boost::bind())时,指向成员函数的指针才是真正有用的
。这将使您能够将函数调用包装为一个对象,以后可以绑定到特定的对象实例,然后作为可复制对象传递。这是一个非常强大的习惯用法,允许延迟回调、委托和复杂的谓词操作。有关一些示例,请参阅我上一篇文章:#include <iostream>
class MemberDemo;
typedef void (MemberDemo::*MemberDemoPtr)();
class MemberDemo
{
public:
void test1();
void test2();
private:
void test1_internal();
void test2_internal();
void do_with_setup_teardown(MemberDemoPtr p);
};
void MemberDemo::test1()
{
do_with_setup_teardown(&MemberDemo::test1_internal);
}
void MemberDemo::test2()
{
do_with_setup_teardown(&MemberDemo::test2_internal);
}
void MemberDemo::test1_internal()
{
std::cout << "Test1" << std::endl;
}
void MemberDemo::test2_internal()
{
std::cout << "Test2" << std::endl;
}
void MemberDemo::do_with_setup_teardown(MemberDemoPtr mem_ptr)
{
std::cout << "Setup" << std::endl;
(this->*mem_ptr)();
std::cout << "Teardown" << std::endl;
}
int main()
{
MemberDemo m;
m.test1();
m.test2();
}
void dosomething(myfoo &m, MFN f){ // m could also be passed by reference to
// const
m.*f();
}
// Button.hpp
#include <memory>
class Button {
public:
Button(/* stuff */) : hdlr_(0), myhandler_(false) { }
~Button() {
// stuff
if (myhandler_) {
delete hdlr_;
}
}
class PressedHandler {
public:
virtual ~PressedHandler() = 0;
virtual void buttonPushed(Button *button) = 0;
};
// ... lots of stuff
// This stores a pointer to the handler, but will not manage the
// storage. You are responsible for making sure the handler stays
// around as long as the Button object.
void setHandler(const PressedHandler &hdlr) {
hdlr_ = &hdlr;
myhandler_ = false;
}
// This stores a pointer to an object that Button does not manage. You
// are responsible for making sure this object stays around until Button
// goes away.
template <class T>
inline void setHandlerFunc(T &dest, void (T::*pushed)(Button *));
private:
const PressedHandler *hdlr_;
bool myhandler_;
template <class T>
class PressedHandlerT : public Button::PressedHandler {
public:
typedef void (T::*hdlrfuncptr_t)(Button *);
PressedHandlerT(T *ob, hdlrfuncptr_t hdlr) : ob_(ob), func_(hdlr) { }
virtual ~PressedHandlerT() {}
virtual void buttonPushed(Button *button) { (ob_->*func_)(button); }
private:
T * const ob_;
const hdlrfuncptr_t func_;
};
};
template <class T>
inline void Button::setHandlerFunc(T &dest, void (T::*pushed)(Button *))
{
PressedHandler *newhandler = new PressedHandlerT<T>(&dest, pushed);
if (myhandler_) {
delete hdlr_;
}
hdlr_ = newhandler;
myhandler_ = true;
}
// UseButton.cpp
#include "Button.hpp"
#include <memory>
class NoiseMaker {
public:
NoiseMaker();
void squee(Button *b);
void hiss(Button *b);
void boo(Button *b);
private:
typedef ::std::auto_ptr<Button> buttonptr_t;
const buttonptr_t squeebutton_, hissbutton_, boobutton_;
};
NoiseMaker::NoiseMaker()
: squeebutton_(new Button), hissbutton_(new Button), boobutton_(new Button)
{
squeebutton_->setHandlerFunc(*this, &NoiseMaker::squee);
hissbutton_->setHandlerFunc(*this, &NoiseMaker::hiss);
boobutton_->setHandlerFunc(*this, &NoiseMaker::boo);
}
object.method();
pointer->method();
int a[100];
a[5]; a[8]; a[23];
a[i];
template<typename TContainer,
typename TProperty,
typename TElement = decltype(*Container().begin())>
TProperty grand_total(TContainer& items, TProperty (TElement::*property)() const)
{
TProperty accum = 0;
for( auto it = items.begin(), end = items.end(); it != end; ++it) {
accum += (it->*property)();
}
return accum;
}
auto ship_count = grand_total(invoice->lineItems, &LineItem::get_quantity);
auto sub_total = grand_total(invoice->lineItems, &LineItem::get_extended_total);
auto sales_tax = grand_total(invoice->lineItems, &LineItem::calculate_tax);