指向任何类类型的非静态成员函数的 C++ 函数指针

Posted

技术标签:

【中文标题】指向任何类类型的非静态成员函数的 C++ 函数指针【英文标题】:C++ function pointer to a non-static member function of any class type 【发布时间】:2017-03-01 23:38:47 【问题描述】:

我已经看到了许多示例,如何使函数指针指向 特定 类类型的 C++ 类非静态成员。但是,我会使用这种适用于 any 类型类的指针。为了演示这个想法,我写了一个伪示例:

class A

    public:
    A() //constructor    
    void callMe()  /* do something */ 
;

class B

    public:
    B() //constructor    
    void callMe()  /* do something */ 
;


main()

    A aa;
    B bb;

    //pseudo part:
    generic_method_pointer_type p; //how to define the type of p?

    p=HOWTO;//set pointer p to point to A::callMe. How to do?

    p(aa); //A::callMe on instance aa gets called

    p=HOWTO;//set pointer p to point to B::callMe. How to do?

    p(bb); //B::callMe on instance bb gets called

这看起来可能吗?

我知道 C++11 对此有新的技巧,例如 std::function。我在 std::function 上做了一些实验,发现它对于在小型微控制器上运行的实时应用程序来说太慢了。这就是为什么我更喜欢直接硬编码的指针,这会导致最小的开销。

感谢您的建议!

【问题讨论】:

您是否阅读了您提供的标签下的帖子,特别是在成员函数指针下? 在网上搜索了几个小时。如果您知道答案的链接,我将不胜感激。 如果您设置p=&A::callMe; 然后执行p(bb);,您期望会发生什么? 您需要知道哪种this 才能调用该方法,这会使您陷入困境。如果你想要一个可以保存任何东西的通用函数指针,这是可以做到的,但是所有类型安全都会消失。除非您非常出色并且非常非常小心,否则您的程序将成为等待发生的意外。您是否考虑过放弃异常宽泛的“amy”,让您真正需要解决问题的所有类扩展一个定义函数接口的纯虚拟基类? @aschepler 可能不会有任何好处,但不是问题,因为它很容易避免。 【参考方案1】:

从 MBED 项目源代码(他们的 FunctionPointer 类)中找到了一个完美的解决方案:

https://developer.mbed.org/cookbook/FunctionPointer https://github.com/Seeed-Studio/mbed_ble/blob/master/mbed-src/api/FunctionPointer.h https://github.com/Seeed-Studio/mbed_ble/blob/master/mbed-src/common/FunctionPointer.cpp

工作示例:

A foo;
FunctionPointer  cb;
cb.attach(&foo,&A::callMe);
for(i=0;i<100000000;i++) //callback overhead test
    cb.call();

FunctionPointer 中的代码对我来说不是很明显它是如何工作的。它 memcpy 一些数据等。如果可以简化并加快速度,有什么想法吗?与固定类类型的情况相比,它仍然会导致更多的开销,例如:

A foo;
typedef void (A::*MethodPtr) ();
MethodPtr method = &A::callMe;
Foo *obj = &foo;
for(i=0;i<100000000;i++) //callback overhead test
    (obj->*method)();

当 callMe 仅包含 asm("nop") 时,上述方法比 FunctionPointer 方法快约 4 倍。 x86 和 GCC 的一些基准测试:

直接调用 205 毫秒 上述函数指针示例 258 ms 函数指针示例 1049 毫秒 std::function 3951 毫秒

非常感谢任何优化想法!

【讨论】:

查看FPointer,你可以去掉所有c_callback,因为你总是有一个对象,如果你相信自己所有的NULL指针检查。这里发生的是我上面所说的“所有类型的安全性都消失了”的东西。你可以打包任何你想要的东西,然后祈祷你做对了,因为编译器无法帮助你。 发现 MBED 回调类执行此操作的效率更高一些,但性能差异不是很显着。在大约 900 毫秒内运行测试。删除检查也可以节省几毫秒。

以上是关于指向任何类类型的非静态成员函数的 C++ 函数指针的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer 5th笔记(chap 19 特殊工具与技术)类成员指针

this指针是指向虚函数表的指针

提升 C++。将带有签名指针的成员函数指针传递给函数

访问静态成员函数中的非静态成员的解决方法

C++虚函数

C++|详解类成员指针:数据成员指针和成员函数指针及应用场合