今天遇到一个包含如标题般多种元素掺杂的问题,不仔细揣摩还是很难发现问题的啊。 主要情景如下: 在一个需要委托,绑定到类成员函数的情况下,需要检查该对象的生命周期,便有了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];};新闻热点
疑难解答