多重继承、this、dynamic_cast、static_cast的问题

来源:互联网 发布:天正看图软件 编辑:程序博客网 时间:2024/05/16 10:43

今天遇到一个包含如标题般多种元素掺杂的问题,不仔细揣摩还是很难发现问题的啊。
主要情景如下:
在一个需要委托,绑定到类成员函数的情况下,需要检查该对象的生命周期,便有了SafeHookManager类,该类主要是有两个函数,参数便是检查的对象的指针。

void SafeHookManager::hook(void*);void SafeHookManager::unhook(void*);

下面是我整理出来的出现问题的情况:

class BaseA{public:    virtual void funA(){}    BaseA(){        std::cout<<"BaseA:"<<this<<" static_cast:"<<static_cast<void*>(this)<<std::endl;    }    int a0;};template<typename T>class BaseB{public:    virtual void funB(){}    BaseB(){        std::cout<<"BaseB:"<<this<<" static_cast:"<<static_cast<void*>(this)<<" static_cast T:"<<static_cast<T*>(this)<<" dynamic_cast T:"<<dynamic_cast<T*>(this)<<std::endl;    }    char b[20];};class BaseC{public:    virtual void funC(){}    BaseC(){        std::cout<<"BaseC:"<<this<<" static_cast:"<<static_cast<void*>(this)<<std::endl;    }    int c;};class child:public BaseC,public BaseA,public BaseB<child>{public:    void funB() override {}    child(){        std::cout<<"child:"<<this<<" static_cast:"<<static_cast<void*>(this)<<std::endl;    }};int main(){    child *pChild = new child;    BaseB<child>* pB = static_cast<BaseB<child>*>(pChild);    std::cout<<"child:"<<pChild<<" BaseB:"<<pB<<" dynamic_cast T:"<<dynamic_cast<child*>(pB)<<std::endl;    return 0;}

实际上的我的SafeHookManager::hook和SafeHookManager::unhook一般会分别出现在BaseA、BaseB、BaseC的构造和析构函数里调用,那穿进去的指针就必须child的指针。那上面的代码执行后得到如下结果:
这里写图片描述

第一个问题:child分别按顺序继承BaseC、BaseA、BaseB,所以BaseC的this指针和child的地址一致,BaseA、BaseB的this指针分别包含了前面类大小的偏移。
第二个问题:在构造函数里面调用dynamic_cast进行下行转换时会得到0x00000000,是因为BaseB在构造的时候,child还没有构造,所以这时动态类型检查得不到child的指针,二static_cast却可以跟进偏移计算出child的指针。

如果要正确是使用SafeHookManager::hook和SafeHookManager::unhook,类似像child这样的类就一定要继承BaseB<child>,BaseB定义如下:

template<typename T>class BaseB{public:    BaseB(){        SafeHookManager::hook(static_cast<T*>(this))    }    ~BaseB(){        SafeHookManager::unhook(static_cast<T*>(this))    }    char b[20];};
0 0