指向派生类成员函数的指针,但不是派生(虚拟)函数

Posted

技术标签:

【中文标题】指向派生类成员函数的指针,但不是派生(虚拟)函数【英文标题】:Pointer to member function of derived class, but not derived(virtual) function 【发布时间】:2016-12-27 15:25:29 【问题描述】:

我有一个特定的问题要解决,我不确定是否可行,因为我找不到任何信息或正在解决的示例。 基本上,我有:

class ParentObject ;

class DerivedObject : public ParentObject

    void myFunction()
;

class OtherDerivedObject : public ParentObject

   void myOtherFunction()
;

并想要一个指向 ParentObject::* 的函数指针,并让它能够从任一派生类中获取函数。 我想这样做的原因,我还有一门课

class functionRegistry

  std::map<string, *functionPoint> functionMap;

并且每个对象(最好在 ParentObject 中,但必要时可以在派生对象中单独执行)都有一个 functionRegistry 的实例,我需要 functionPoint 能够指向 DerivedObject 或 OtherDerivedObject 类型的对象中的函数。

提前致谢

【问题讨论】:

在我看来像 a classic XY problem。 您能否详细说明一下您的用例是什么? 好的,我现在有一个解决方案(如下),但出于兴趣考虑:我正在使用基于组件实体的架构编写游戏引擎,其中组件通过简单的消息相互通信。消息由 FORCE_X+50 之类的内容组成,我将在其中将消息解析为:前半部分将与函数相关,后半部分将作为参数。我认为这样它为我创建了一个灵活的环境,可以轻松添加我需要的功能。不同的组件会接受不同的消息并做不同的事情。 例如,物理组件将采用 FORCE_Y-10 消息(或矢量力等),图形将采用 ANIMSPEED_-1 或 ANIMCHANGE_JUMP 之类的东西。似乎比无休止的硬编码 if 语句或其他东西更好。 显然所有这些函数都有相同的签名,对吧?那么为什么不简单地将 ``std::function (或您的函数具有的任何签名)实例存储到您的注册表中。它也应该适用于指向函数成员类型的指针。 【参考方案1】:

您只需要一个static_cast 即可使用正确的类型填充地图。

using pfunc_type = void (ParentObject::*)() ;
pfunc_type pfunc1 = static_cast<pfunc_type>(&DerivedObject::myFunction);

因为这是标准允许的:

[expr.static.cast/12] - §5.2.9¶12

类型为“指向 cv1 T 的 D 成员的指针”类型的纯右值可以是 转换为“指向 cv2 T 类型的 B 成员的指针”类型的纯右值, 其中 B 是 D 的基类(子句 [class.derived]),如果 cv2 是 与 cv1.72 相同的 cv-qualification 或更高的 cv-qualification If 没有从“指向 T 类型 B 成员的指针”的有效标准转换 对于“指向类型 T 的 D 成员的指针”存在 ([conv.mem]),程序 格式不正确。空成员指针值([conv.mem])被转换 到目标类型的空成员指针值。如果 B 级 包含原始成员,或者是 包含原始成员的类,结果指向成员的指针 指向原始成员。否则,行为未定义。 [ 注意:虽然 B 类不需要包含原始成员,但 通过指针间接寻址的对象的动态类型 对成员执行必须包含原始成员;见 [expr.mptr.oper]。 ——尾注]

虽然这是允许的,但您必须非常小心,确保将指向成员的指针应用到具有正确动态类型的对象上。

【讨论】:

为什么行为未定义?为什么不能是编译错误? @Mikhail - 假设一个函数接受一个基类的成员函数和一个指向基类对象的指针。您将如何在编译时检查此约束是否成立? @StoryTeller 抱歉,您确定您没有在这个问题中打错字吗?您有指向成员函数的指针和指向对象的指针的基类。 @Mikhail - 没错,我的意思是something like this。如何静态检查任意成员函数是否存在于任意子类中?我不认为随着程序复杂性的增加,每种情况都有可能。将其保留为 UB 是该标准具有 IMO 的最佳选择。如果使用得当,检查很少,但灵活性很大。 @Chrysm_Seal 既然答案是“优秀”,你为什么不接受呢? :)

以上是关于指向派生类成员函数的指针,但不是派生(虚拟)函数的主要内容,如果未能解决你的问题,请参考以下文章

为啥指向基类的派生类指针可以调用派生类成员函数? [复制]

基类指针指向派生类对象&派生类指针指向基类对象

为啥我可以通过指向派生对象的基类指针访问派生私有成员函数?

在基类中存储指向派生类函数的指针

在 C++ 中将指向基类的指针传递给派生类的成员函数

基类与派生类的指针和成员函数调用原理