【问题标题】:How Can I Pass a Member Function to a Function Pointer?如何将成员函数传递给函数指针?
【发布时间】:2021-11-29 10:29:44
【问题描述】:
class Child;
class Parent
{
public:
  void (*funcPointer)();
  void (*funcPointer2)(Parent* _this);
  void (Child::*funcPointer3)();
};

class Child: public Parent
{
public:
  void TestFunc(){

  }
  void Do(){
    Parent p;
    p.funcPointer=TestFunc; // error, '=': cannot convert from 'void (__thiscall Child::* )(void)' to 'void (__cdecl *)(void)'
    p.funcPointer2=TestFunc; // error too, '=': cannot convert from 'void (__thiscall Child::* )(void)' to 'void (__cdecl *)(Parent *)'
    p.funcPointer3=TestFunc; //this works
    p.funcPointer3=&Child::TestFunc; // this works too.
    p.funcPointer3();    // error, term does not evaluate to a function taking 0 arguments
  }
};

如何将成员函数传递给函数指针,然后如何调用该函数指针?

【问题讨论】:

标签: c++ methods function-pointers member-function-pointers delayed-execution


【解决方案1】:

随着 bindLambda Functions 的出现,我们实际上可以在 C++11 中完成所有 3 个 funcPointer*s。让我们先谈谈每一个,并讨论他们在做什么:

  1. funcPointer 试图调用Child 方法 不接收Child 对象,因此必须保存Child 对象。子对象可以通过指针保存:bind(&Child::TestFunc, this) 或者在 C++14 中可以通过值保存:[arg = *this]() mutable { arg.TestFunc(); }
  2. funcPointer2 试图用 Parent* 调用 Child 方法。我们可以这样做:[](Parent* arg){ static_cast<Child*>(arg)->TestFunc(); } 当然这不会比(new Parent)->TestFunc() 更合法所以我们假设Parent* 实际上是Child*,如果你愿意让Parent Polymorphic Type 您可以在调用 lambda 之前进行验证:
[](Parent* arg) {
    assert(dynamic_cast<Child*>(arg) != nullptr);

    static_cast<Child*>(arg)->TestFunc();
}
  1. funcPointer3 试图存储一个指向 Child 方法的指针,而您已经完成了这项工作。您只需要使用Child 对象来调用它,例如:(this-&gt;*p.funcPointer3)()。但是您必须像这样分配funcPointer3funcPointer3 = &amp;Child::TestFunc,因为如果您尝试这样做:funcPointer3 = &amp;TestFunc,您将收到错误:

'&':对绑定成员函数表达式的非法操作

接下来,函数指针或成员函数指针不能用于引用Closure Type,因此我们需要将函数指针转换为function 对象。 (funcPointer3只是一个成员函数指针,所以不需要转换,但我会转换它来证明function对象可以包含一个成员函数指针,它简化了对p.funcPointer(this))的调用:

class Parent {
public:
    function<void()> funcPointer;
    function<void(Parent*)> funcPointer2;
    function<void(Child*)> funcPointer3;
};

现在我们已经适应了Parent,我们可以轻松地分配,如123所示:

void Child::Do() {
    Parent p;

    p.funcPointer = bind(&Child::TestFunc, this);
    p.funcPointer2 = [](Parent* arg) { static_cast<Child*>(arg)->TestFunc(); };
    p.funcPointer3 = &Child::TestFunc;
    p.funcPointer();
    p.funcPointer2(this);
    p.funcPointer3(this);
}

您可能知道这一点并且只是在测试,但我们可以轻松地使用继承自 ChildParent 的成员,就像我们可以在 Child::Do 中创建一个新的 Parent 对象一样。我将切换它并在示例中抛出代码:http://ideone.com/yD7Rom

【讨论】:

    【解决方案2】:

    为了响应您上次的编辑,要形成指向成员的指针,您必须使用 &amp;classkey::。对于普通函数,没有与函数名称等效的指针到函数的隐式转换。

    // not valid:
    p.funcPointer3=TestFunc;
    
    // valid:
    p.funcPointer3 = &Child::TestFunc;
    

    要通过指向成员的指针访问成员,您必须使用 .*-&gt;* 运算符。

    例如

    (this->*p.funcPointer3)();
    

    【讨论】:

    • 这确实有效,我必须告诉编译器成员函数指针使用哪个对象。谢谢!
    • @lovespring 这是 C++11 之前的最佳答案,真的不需要用 Boost 来膨胀你的可执行文件。
    【解决方案3】:

    你不能。您要么将指针传递给静态方法,要么 Parent 也必须接受指向该对象的指针。

    您可能想查看 boost::bindboost::function

    #include <boost/bind.hpp>
    #include <boost/function.hpp>
    struct Y
    {
        void say(void) { std::cout << "hallo!";}
    
        boost::function<void()> getFunc() { return boost::bind(&Y::say, this); }
    };
    
    struct X
    {
        //non-boost:
        void (Y::*func)();
        Y* objectY;
        void callFunc() { (objectY->*func)(); }
    
        //boost version:
        boost::function<void()> f;
    
    };
    
    
    X x;
    Y y;
    x.f = boost::bind(&Y::say, boost::ref(y));
    x.f = y.getFunc();
    x.f();
    x.func = &Y::say;
    x.objectY = &y; 
    x.callFunc();
    

    【讨论】:

    • 还添加了非增强版本。
    • 这真的是我想要的!我现在在 Visual Studio C++ 6 中编码,我不确定它是否支持 boost::bind 和 boost:function。你知道吗?
    • 我添加了所需的包含,因此您只需要获取 boost 并尝试一下。但是貌似boostpro.com/download不支持VS6.0,但这并不意味着bind和function不能在那里工作。
    • 我可以补充一点,MSVS 2010 或 GCC 4.4+ 增加了对 C++0X 中的std::functionstd::bind 的支持,这是一种面向未来的标准方式来做这种事情。
    • 好点。但是这个功能绝对不会在 MSVC6 中可用:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 2017-05-16
    相关资源
    最近更新 更多