具有虚拟性的多级层次结构可防止转换函数指针

Posted

技术标签:

【中文标题】具有虚拟性的多级层次结构可防止转换函数指针【英文标题】:Multilevel hierarchy with virtuality prevents casting function pointers 【发布时间】:2016-10-16 18:40:34 【问题描述】:

我创建了一些类层次结构,其中的基类(在以下示例中:clA)定义了从executor 例程调用的函数指针。反过来,作为回调传递executor 的代码不知道它在哪种类型的派生对象上运行(clB 只是其中之一)。如果派生类没有实现某些函数,它不会强制转换为函数指针,并且在调用 executor 时不会发生任何事情。还有一些虚函数(clA 实际上是纯虚函数)。我的类看起来与此类似(无法呈现实际代码,因此我创建了简化的演示):

class clA

protected:
    INT_PTR(__stdcall clA::*Fn1)(int);
    INT_PTR(__stdcall clA::*Fn2)(int);
    static INT_PTR CALLBACK executor(UINT operation, int opData, clA *ptr = NULL)
    
        switch (operation)
        
        case 1:
            if (ptr->Fn1)
            
                typedef INT_PTR(__stdcall clA::*FPtr)(int);
                FPtr funcPtr = ptr->Fn1;
                return (ptr->*funcPtr)(opData);
            
            break;
        case 2:
            if (ptr->Fn2)
            
                typedef INT_PTR(__stdcall clA::*FPtr)(int);
                FPtr funcPtr = ptr->Fn2;
                return (ptr->*funcPtr)(opData);
            
            break;
        
    
public:
    clA()  Fn1 = NULL; Fn2 = NULL; 
    virtual BOOL vrt(void) = 0;
;

class clB : public clA

    INT_PTR __stdcall ImplFn1(int)  return 0; 
    INT_PTR __stdcall ImplFn2(int)  return 0; 
public:
    void testing(void);
    clB()
    
        Fn1 = reinterpret_cast <INT_PTR(__stdcall clA::*)(int)> (&clB::ImplFn1);
        Fn2 = reinterpret_cast <INT_PTR(__stdcall clA::*)(int)> (&clB::ImplFn2);
    
    BOOL vrt(void)  return FALSE; ;
;

到目前为止一切正常,直到今天我决定我需要基类 clA 来继承其他类,让它成为 clExtra,所以我做了以下更改:

class clExtra

public:
   static int x;
;

//now class clA is deriving from clExtra
class clA : public clExtra

问题

现在我有以下编译错误:

inheritancetest.h(49): error C2440: 'reinterpret_cast' : cannot convert from 'INT_PTR (__stdcall clB::* )(int)' to 'INT_PTR (__stdcall clA::* )(int)'
Pointers to members have different representations; cannot cast between them

我真的不明白它们是如何突然变成不同的表示的。 MSDN 的可能 C2440 原因示例不适用。奇怪的是,如果我从 clA 类中删除任何虚拟性,我也可以让它编译。如果有人了解可能导致我无法投射的原因,我将永远感激您的解释。

【问题讨论】:

【参考方案1】:

我认为这是 VC++ 中的错误。它在 gcc 中 compiles successfully。

static_cast 足以完成这种类型的转换。

我发现 VC++ 在使用 static_cast 而不是 reinterpret_cast 时不会报错。

【讨论】:

你说得对,我可以用 static_cast 替换所有演员表,但我想避免它,因为它们太多了......重新设计 1000 个构造函数仍然比重新工作要快不过,请等待可能的错误确认。我会解决的,同时也许有类似经验的其他人会阅读这篇文章 @Kitet 你为什么不想使用static_cast?表现?我认为在这种情况下不会插入额外的指令,因为它们不需要。如果您想 100% 确定,请查看生成的程序集。 你一定是误会了什么。我将它们全部切换为静态,花了 2 个小时完成所有构造函数和一些测试。

以上是关于具有虚拟性的多级层次结构可防止转换函数指针的主要内容,如果未能解决你的问题,请参考以下文章

类型转换

函数指针转换为 void 而不被调用

将函数指针的 C 结构体转换为 JNA 代码

C++:将派生指针转换为 void 指针,然后转换为抽象指针,并访问成员函数

用于编辑具有多级节点和多个用户的层次结构的架构

向下转换指向成员函数的指针