MFC中一个类的成员变量值自动被篡改:多重继承带来的问题
今天发现一个奇葩的bug:
一个类中的某个成员变量的值,在初始化的时候已经赋值为 true
在这里插入代码片了,可是在使用这个类的时候,发现它的值自动变为了 false
。
class SipPhoneController : public IHardwareController, public CWnd
{...public:bool ready;...
}
我在所有涉及到改变量赋值的地方都打上了断点,打算跟踪看看什么地方导致了重新赋值,可是结果却是没有任何断点被触发。
我把 ready
加了监视,单步调试进去,之前一直是 true
,但只要已进入SipPhoneController
的方法,值立马变成了 false
。
担心 SipPhoneController
对象被意外销毁后重建,导致 ready 被重置,又在 SipPhoneController
的构造和析构函数中打上断点,可依旧没有被触发。
还以为又是vs抽风,把项目清理,重新编译,重启vs都无效,,,
直到抱着试试的态度把 SipPhoneController
的继承顺序改了一下,如下:
class SipPhoneController : public CWnd, public IHardwareController
{...public:bool ready;...
}
结果奇迹般就正常了。
那么继承顺序的不同为什么会出现值变化?
可能原因1:this指针偏移
在MFC框架中,当处理消息时,MFC内部会使用CWnd的this指针。如果CWnd不是第一个基类,那么:
// 当MFC调用消息处理函数时,隐含的this指针是基于CWnd部分的
// 如果CWnd不是第一个基类,this指针需要偏移CWnd* pWnd = this; // 这里会发生指针偏移// 在消息处理函数中访问成员变量时,使用的是偏移后的this指针
// 导致访问到错误的内存位置
可能原因2:MFC内部机制
MFC有很多内部实现依赖于CWnd在对象开始位置:
// MFC内部可能有的代码
void SomeMfcInternalFunction(CWnd* pWnd)
{// 假设MFC内部直接通过CWnd指针访问某些数据// 如果CWnd不在对象开头,就会访问到错误的内存SomeData* pData = reinterpret_cast<SomeData*>(pWnd);// 这里如果CWnd不在开头,pData就指向了错误的位置
}
可能原因3:虚函数表问题
如果IHardwareController有虚函数,而CWnd也有虚函数表,多重继承时的虚函数表布局可能会导致问题。