buf

BE something YOU love and understand
posts - 94, comments - 35, trackbacks - 0, articles - 2
   :: 首页 :: 新随笔 :: 联系 ::  :: 管理

MFC 多继承 基类顺序问题

Posted on 2010-06-14 15:54 buf 阅读(1058) 评论(1)  编辑 收藏 引用 所属分类: MFC
最近在看四人帮的设计模式,看到Observer一章,想动手操练一下。以时间源为Subject,数字时钟和模拟时钟为Observer,在VC6.0SP6下新建了一个基于对话框的工程,下面是代码片断:
class Observer  
{
public:
    Observer();
    virtual ~Observer();

    virtual void Update() = 0;
};

class CAnalogClock : public Observer, public CStatic
{
// Construction
public:
    CAnalogClock();

// Attributes
public:

// Operations
public:
    void Update()
    {
        // get data from subject
        // 
        
        // Update UI
        Invalidate();
        UpdateWindow();
    }

// Other stuff 
};

CAnalogClock在Update方法中更新时间数据,然后在强制刷新界面。为了绘制模拟时钟,还需要重载WM_PAINT消息的响应函数:
void CAnalogClock::OnPaint() 
{
 CPaintDC dc(this); // device context for painting
 
 // TODO: Add your message handler code here


运行程序出现异常。。。

调试发现CAnalogClock实例的内存模型如下:

addr + 0      vtable_pointer_for_Oberserver
addr + 4      vtable_pointer_for_CCmdTarget
addr + 8      data_member_of_CCmdTarget (0x00000001)
addr + 12    other stuff ...

 在CAnalogClock::OnParint()中设置断点,将this加入监视列表,发现this指针指向addr + 4,但将this展开却发现它被认为指向一个CAnalogClock对象,于是一切都乱套了,0x00000001被认为是指向虚函数表的指针,m_hWnd的值也不对了。。。


在VS2005SP1中调试发现效果一样。

在多继承时,基类的顺序有什么讲究么?待解答。


续前,在定义CAnalogClock类时若将CStatic作为第一基类,即
class CAnalogClock : public CStatic, public Observer {...};
并在CAnalogClock::Update()中设置断点,观察this指针,得到的情况如下:


观察两个虚函数表指针在内存中的位置可以看出,CAnalogClock对象的地址是0x0012fe90,而this指针的值是0x0012fed0,亦被认为是CAnalogClock对象,但展开后各个数据成员的值都是正确的。。。

google了一下,msdn给出了答案,看起来和消息映射的实现有关:

CWnd and Message Maps

For the MFC message map system to work correctly, there are two additional requirements:

  • There must be only one CWnd-derived base class.
  • The CWnd-derived base class must be the first (or left-most) base class.

详见  TN016: Using C++ Multiple Inheritance with MFC

只有注册用户登录后才能发表评论。