深入浅出MFC第2版(PDF格式)-第37部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
IsKindOf 的参数其实就是&CWinApp::classCWinApp 。函数内利用GetRuntimeClass
先取得&CView::classCView,然后循线而上(从图3…1 来看,所谓循线分别是指
CView、CWnd、CCmdTarget、CObject),每获得一个CRuntimeClass 对象指针,就
拿来和CView::classCView 的指针比对。靠这个土方法,完成了IsKindOf 能力。
140
…………………………………………………………Page 203……………………………………………………………
第3章 MFC 六大關鍵技術之模擬
2。 IsKindOf 的使用方式如:
CMyDoc* pMyDoc = new CMyDoc;
CMyView* pMyView = new CMyView;
cout IsKindOf(RUNTIME_CLASS(CMyDoc)); // 應該獲得 TRUE
cout IsKindOf(RUNTIME_CLASS(CDocument)); // 應該獲得 TRUE
cout IsKindOf(RUNTIME_CLASS(CCmdTarget)); // 應該獲得 TRUE
cout IsKindOf(RUNTIME_CLASS(CObject)); // 應該獲得 TRUE
cout IsKindOf(RUNTIME_CLASS(CWinApp)); // 應該獲得 FALSE
cout IsKindOf(RUNTIME_CLASS(CView)); // 應該獲得 FALSE
cout IsKindOf(RUNTIME_CLASS(CView)); // 應該獲得 TRUE
cout IsKindOf(RUNTIME_CLASS(CObject)); // 應該獲得 TRUE
cout IsKindOf(RUNTIME_CLASS(CWnd)); // 應該獲得 TRUE
cout IsKindOf(RUNTIME_CLASS(CFrameWnd)); // 应该获得FALSE
IsKindOf 的完整范例放在Frame4 中。
Frame4 范例程序
Frame4 与Frame3 大同小异,唯一不同的就是前面所说的,在CObject 中加上IsKindOf 函
数的声明与定义,并将私有类别(non…MFC 类别)也挂到「类别型录网」中:
// in header file
class CMyFrameWnd : public CFrameWnd
{
DECLARE_DYNAMIC(CMyFrameWnd) // 在MFC 程序中这里其实是DECLARE_DYNCREATE()
。。。 // 稍后我便会仿真DECLARE_DYNCREATE() 给你看
};
class CMyDoc : public CDocument
{
DECLARE_DYNAMIC(CMyDoc) // 在MFC 程序中这里其实是DECLARE_DYNCREATE()
。。。 // 稍后我便会仿真DECLARE_DYNCREATE() 给你看
};
class CMyView : public CView
{
DECLARE_DYNAMIC(CMyView) // 在MFC 程序中这里其实是DECLARE_DYNCREATE()
。。。 // 稍后我便会仿真DECLARE_DYNCREATE() 给你看
};
141
…………………………………………………………Page 204……………………………………………………………
第篇 勿在浮砂築高台
// in implementation file
。。。
在 程序中这里其实是
IMPLEMENT_DYNAMIC(CMyFrameWnd; CFrameWnd) // MFC IMPLEMENT_DYNCREATE ()
// 稍后我便会仿真IMPLEMENT_DYNCREATE () 给你看
。。。
IMPLEMENT_DYNAMIC(CMyDoc; CDocument) //
在 程序中这里其实是
MFC IMPLEMENT_DYNCREATE()
// 稍后我便会仿真IMPLEMENT_DYNCREATE() 给你看
。。。
在 程序中这里其实是
IMPLEMENT_DYNAMIC(CMyView; CView) // MFC IMPLEMENT_DYNCREATE()
// 稍后我便会仿真IMPLEMENT_DYNCREATE() 给你看
我不在此列出Frame4 的源代码,你可以在书附光盘片中找到完整的文件。Frame4 的命
令列编译联结动作是(环境变量必须先设定好,请参考第4章的「安装与设定」一节):
cl my。cpp mfc。cpp
以下即是Frame4 的执行结果:
pMyDoc…》IsKindOf(RUNTIME_CLASS(CMyDoc)) 1
pMyDoc…》IsKindOf(RUNTIME_CLASS(CDocument)) 1
pMyDoc…》IsKindOf(RUNTIME_CLASS(CCmdTarget)) 1
pMyDoc…》IsKindOf(RUNTIME_CLASS(CObject)) 1
pMyDoc…》IsKindOf(RUNTIME_CLASS(CWinApp)) 0
pMyDoc…》IsKindOf(RUNTIME_CLASS(CView)) 0
pMyView…》IsKindOf(RUNTIME_CLASS(CView)) 1
pMyView…》IsKindOf(RUNTIME_CLASS(CObject)) 1
pMyView…》IsKindOf(RUNTIME_CLASS(CWnd)) 1
pMyView…》IsKindOf(RUNTIME_CLASS(CFrameWnd)) 0
pMyWnd…》IsKindOf(RUNTIME_CLASS(CFrameWnd)) 1
pMyWnd…》IsKindOf(RUNTIME_CLASS(CWnd)) 1
pMyWnd…》IsKindOf(RUNTIME_CLASS(CObject)) 1
pMyWnd…》IsKindOf(RUNTIME_CLASS(CDocument)) 0
142
…………………………………………………………Page 205……………………………………………………………
第3章 MFC 六大關鍵技術之模擬
Dynamic Creation (动态生成)
基础有了,做什么都好。同样地,有了上述的「类别型录网」,各种应用纷至沓来。其
中一个应用就是解决棘手的动态生成问题。
我已经在第二章描述过动态生成的困难点:你没有办法在程序执行期间,根据动态获得
的一个类别名称(通常来自读档,但我将以屏幕输入为例),要求程序产生一个对象。
上述的「类别型录网」虽然透露出解决此一问题的些微曙光,但是技术上还得加把劲儿。
如果我能够把类别的大小记录在类别型录中,把构造函数(注意,这里并非指C++ 构造
式,而是指即将出现的CRuntimeClass::CreateObject)也记录在类别型录中,当程序在执
行时期获得一个类别名称,它就可以在「类别型录网」中找出对应的元素,然后调用其
构造函数(这里并非指C++ 构造式),产生出对象。
好主意!
类别型录网的元素型式CRuntimeClass 于是有了变化:
// in MFC。H
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL =》 abstract class
CRuntimeClass* m_pBaseClass;
CObject* CreateObject();
static CRuntimeClass* PASCAL Load();
// CRuntimeClass objects linked together in simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
143
…………………………………………………………Page 206……………………………………………………………
DECLARE_DYNCREATE /IMPLEMENT_DYNCREATE 宏
为了因应CRuntimeClass 中新增的成员变量, 我们再添两个宏,
DECLARE_DYNCREATE 和IMPLEMENT_DYNCREATE:
#define DECLARE_DYNCREATE(class_name)
DECLARE_DYNAMIC(class_name)
static CObject* PASCAL CreateObject();
#define IMPLEMENT_DYNCREATE(class_name; base_class_name)
CObject* PASCAL class_name::CreateObject()
{ return new class_name; }
_IMPLEMENT_RUNTIMECLASS(class_name; base_class_name; 0xFFFF;
class_name::CreateObject)
于是,以CFrameWnd 为例,下列程序代码:
// in header file
class CFrameWnd : public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
。。。
};
// in implementation file
IMPLEMENT_DYNCREATE(CFrameWnd; CWnd)
就被展开如下(注意,编译器选项/P 可得前置处理结果):
// in header file
class CFrameWnd : public CWnd
{
public:
static CRuntimeClass classCFrameWnd;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
。。。
};
// in implementation file
CObject* PASCAL CFrameWnd::CreateObject()
{ return new CFrameWnd; }
144
…………………………………………………………Page 207……………………………………………………………
static char _lpszCFrameWnd'' = 〃CFrameWnd〃;
CRuntimeClass CFrameWnd::classCFrameWnd = {
_lpszCFrameWnd; sizeof(CFrameWnd); 0xFFFF; CFrameWnd::CreateObject;
RUNTIME_CLASS(CWnd); NULL };
static AFX_CLASSINIT _init_CFrameWnd(&CFrameWnd::classCFrameWnd);
CRuntimeClass* CFrameWnd::GetRuntimeClass() const
{ return &CFrameWnd::classCFrameWnd; }
图示如下:
C O b j e c t : : c l a s s C O b j e c t C C m d T a r g e t : : c l a s s C C m d T a r g e t C W i n T h r e a d : : c l a s s C W i n T h r e a d
“ C O b j e c t ” “ C C m d T a r g e t ” “ C W in T h r e a d ”
m _ p B a s e C la s s m _ p B a s e C la s s m _ p B a s e C la s s
m _ p N e x t C la s s m _ p N e x t C la s s m _ p N e x t C la s s
N U L L
N U L L
C F r a m e W n d : : c l a s s C F r a m e W n d C W n d : : c l a s s C W n d C W i n A p p :