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);