Posted on 2010-06-14 15:54
buf 阅读(1075)
评论(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