深入浅出MFC学习笔记第三章MFC六大关键技术之仿真类型识别动态创建.docx
《深入浅出MFC学习笔记第三章MFC六大关键技术之仿真类型识别动态创建.docx》由会员分享,可在线阅读,更多相关《深入浅出MFC学习笔记第三章MFC六大关键技术之仿真类型识别动态创建.docx(31页珍藏版)》请在冰豆网上搜索。
深入浅出MFC学习笔记第三章MFC六大关键技术之仿真类型识别动态创建
第三章:
MFC六大关键技术之仿真:
类型识别
深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。
要模仿的六大技术包括:
1:
MFC程序的初始化过程。
2:
RTTI(Runtimetypeidentification)运行时类型识别。
3:
Dynamiccreation动态创建
4:
Persistence永久保存
5:
消息映射
6:
消息传递。
RTTI(运行时类型识别)
IsKindOf能够侦测某个对象是否属于某种类。
即判断某一对象所属的类是否是父类或当前类;
要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。
MFC以链表的方式建立了此表。
类型型录表的每个元素为CRuntimeClass类型,其定义为:
[cpp]viewplaincopy
1classCRuntimeClass
2
3{
4
5public:
6
7LPCSTRm_lpszClassName;//对象所属类名
8
9Intm_nObjectSize;//对象大小
10
11UINTm_wSchema;//模式号
12
13CObject*(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULL
14
15CRuntimeClass*pBaseClasss;//基类CRuntimeClass对象指针。
16
17StaticCRuntimeClass*pFirstClass;//链表头指针。
18
19CRuntimeClass*m_pNextClass;//下一指针。
20
21};
MFC使用此类作为每个类的成员变量。
使用宏定义为每个类定义了自己的CRuntimeClass成员变量。
DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏
使用这两个宏将CRuntimeClass对象不知不觉放到类之中。
DECLARE_DYNMIC宏定义如下:
[cpp]viewplaincopy
22#defineDELCARE_DYNMIC(class_name)\
23
24public:
\
25
26staticCRuntimeClassclass##class_name\
27
28virtualCRuntimeClass*GetRuntimeClass()const;
##用来告诉编译器把两个字符串连接起来。
如果使用这个宏:
DELCARE_DYNMIC(CView);
那么预编译器将生成下列代码:
[cpp]viewplaincopy
29public:
30
31staticCRuntimeClassclassCView;
32
33virtualCRuntimeClass*GetRuntimeClass()const;
以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。
注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。
初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。
[cpp]viewplaincopy
34#defineIMPLEMENT_DYNMIC(class_name,base_class_name)\
35
36_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL);
37
38_IMPLEMENT_RUNTIMECLASS又是一个宏,它定义如下:
39
40#define_IMPLEMENT_RUNTIMECLASS(class_name,\
41
42base_class_name,wSchema,pfnNew)\
43
44staticchar_lpsz##class_name[]=#class_name;\
45
46CRuntimeClassclass_name:
:
class##class_name=\
47
48{_lpsz##class_name,sizeof(class_name),\
49
50wSchema,pfnNew,\
51
52RUNTIME_CLASS(base_class_name),NULL\
53
54};
55
56staticAFX_CLASSINIT_init##class_name\
57
58(&class_name:
:
class##class_name);\
59
60CRuntimeClass*class_name:
:
GetRuntimeClass()const\
61
62{\
63
64return&class_name:
:
class##classname;\
65
66}
67
68#defineRUNTIME_CLASS(class_name)\
69
70(&class_name:
:
class##class_name);
AFX_CLASSINIT是一个类,看着跟宏定义似的,这样做很容易让人迷惑。
它用于将本节点连接到类型型录表,定义如下:
[cpp]viewplaincopy
71classAFX_CLASSINIT
72
73{
74
75public:
76
77AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数
78
79{
80
81pNewClass->m_pNextClass=CRuntime:
:
pFirstClass;
82
83CRuntimeClass:
:
pFirstClass=pNewClass;
84
85}
86
87};
用法:
[cpp]viewplaincopy
88classCWnd:
publicCCmdTarget
89
90{
91
92public:
93
94DECLARE_DYNAMIC(CWnd);
95
96
97};
IMPLEMENT_DYNMIC(CWnd,CCmdTarget);
代码展开后为;
[cpp]viewplaincopy
98classCWnd:
publicCCmdTarget
99
100{
101
102public:
103
104staticCRuntimeClassclassCView;
105
106virtualCRuntimeClass*GetRuntimeClass()const
107
108
109
110};
111
112
113
114staticchar_lpszCWnd[]="CWnd";
115
116CRuntimeClassCWnd:
:
classCWnd=
117
118{
119
120_lpszCView,sizeof(CWnd),FFFF,NULL,&Wnd:
:
classCWnd,NULL);
121
122};
123
124staticAFX_CLASSINIT_init_CWnd(&CWnd:
:
classCWnd);
125
126{
127
128Return&CWnd:
:
classCWnd;
129
130}
定义宏的过程很复杂,但是一旦定义好之后,在使用时仅仅两句话就可以完成定义CRuntimeClass对象并且连接类型型录链表的工作。
CObject是所有类的基类,也是链表的头,此类应特别定义,不能在CObject内使用定义好的宏。
[cpp]viewplaincopy
131classCObject
132
133{
134
135public:
136
137virtualCRuntimeClass*GetRuntimeClass()const;
138
139staticCRuntimeClassclassCObject;
140
141};
142
143staticcharszCobject[]="CObject";
144
145structCRuntimeClassCObject:
:
classCObject=
146
147{
148
149szCObject,sizeof(CObject),0xFFFF,NULL,NULL,NULL
150
151};
152
153staticAFX_CLASSINIT_init_CObject(&Cobject:
:
classObject);
154
155CRuntimeClass*CObject:
:
GetRuntimeClass()const
156
157{
158
159return&CObject:
:
classCObject;
160
161}
由于CRuntimeClass对象是static成员变量,因此需要在类外初始化。
如果忘记初始化将会报链接错误。
CRuntimeClass*CRuntimeClass:
:
pFirstClass=NULL;
建好了类类型路表,要实现IsKindOf功能很容易。
首先在CObject加上一个IsKindOf函数,于是所有继承自此类的类都具有类型识别的功能。
能够将某个CRuntimeClass对象与类类型型录中的元素进行比较。
如:
[cpp]viewplaincopy
162classCObject
163
164{
165
166public:
167
168boolIsKindOf(constCRuntimeClass*pClass)const
169
170{
171
172CRuntimeClass*pClassThis=GetRuntimeClass();
173
174while(pClassThis)
175
176{
177
178if(pClassThis==pClass)
179
180returntrue;
181
182pClassThis=pClassThis->m_pBaseClass;//沿着基类寻找。
183
184}
185
186returnfalse;
187
188}
189
190};
如果我们调用CWnd*cw=newCWnd;
cw->IsKindOf(RUNTIME_CLASS(CFrameWnd));
RUNTIME_CLASS实际就是&CFrameWnd:
:
classCFrameWnd,它就是CFrameWnd的static的CRuntimeClass类型成员。
函数内利用GetRuntimeClass取得本类的CRuntimeClass对象的地址,即&CWnd:
:
classCWnd,然后进行比较。
因为每一类型共用一个static的CRuntimeClass对象,因此属于同于类的CRuntimeClass对象的地址相同。
动态创建
每一类的构建函数可以记录在类型别录中,当获得一个类名称,通过查找类别型录表找出对应的元素,然后调用其构建函数产生新对象。
在CRuntimeClass中m_pfnCreateObject即为构建函数首地址。
为了实现动态创建,需要添加两个宏:
DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE。
如:
[cpp]viewplaincopy
191#defineDECLARE_DYNCREATE(class_name)\
192
193DECLARE_DYNCREATE(class_name)\
194
195staticCObject*PASCALCreateObject();
196
197#defineIMPLEMENT_DYNCREATE(class_name,base_class_name)\
198
199CObject*PASCALclass_name:
:
CreateObject()\
200
201{returnnewclassname;};\
202
203_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,
204
2050xFFFF,class_name:
:
CreateObject)
以CFrameWnd为例,下列程序代码:
[cpp]viewplaincopy
206classCFrameWnd:
publicCWnd
207
208{
209
210public:
211
212DECLEARE_DYNCREATE(CFrameWnd);
213
214};
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd);
展开如下:
[cpp]viewplaincopy
215classCFrame:
publicCWnd
216
217{
218
219public:
220
221staticCRuntimeClassclassCFrameWnd;
222
223virtualCRuntimeClass*GetRuntimeClass()const;
224
225staticCObject*PASCALCreateObject();
226
227};
228
229CObject_PASCALCFrameWnd:
:
CreateObject()
230
231{
232
233returnnewCFrameWnd;
234}
235
236staticchar_lpszCFrameWnd[]="CFrameWnd";
237
238CRuntimeClassCFrameClass:
:
classCFrameWnd={
239
240_lpszCFrameWnd,sizeof(CFrameWnd),0xFFFF,CFrameWnd:
:
CreateObject,RUNTIME_CALSS(CWnd),NULL};
241
242staticAFX_CLASSINIT_init_CFrameWnd
243
244(&CFrameWnd:
:
classCFrameWnd);
245
246CRuntimeClass*CFrameWnd:
:
GetRunimeClass()const
247
248{return&CFrameWnd:
:
classCFrameWnd;}
注意对象构建函数为static函数。
为了支持动态创建需要在CRuntimeClass内添加两个函数:
CreateObject和CRuntimeClass:
:
Load成员函数。
[cpp]viewplaincopy
249CObject*CRuntimeClass:
:
CreateObject()
250
251{
252
253If(m_pfnCreateObject==NULL)//不支持动态创建。
254
255{
256
257throwruntime_error("此类不支持动态创建");
258
259ReturnNULL;
260
261}
262
263CObject*pObject=(*m_pfnCreateObject)();
264
265ReturnpObject;
266
267}
268
269CRuntimeClass*PASCLCRuntimeClass:
:
Load()
270
271{
272
273CharszClassName[64];
274
275CRuntimeClass*pClass
276
277cout<<"输入一个类名:
";
278
279cin>>szClassName;
280
281for(pClass=pFirstClass;pClass;pClass=pClass->m_pNextClass)
282
283{
284
285if(strcmp(szClassName,pClass->m_lpszClassName)==0)
286
287returnpClass;
288
289returnNULL;
290
291}
292
293}
以下为类型识别及动态创建的完整代码:
[cpp]viewplaincopy
29418px;">#include
295#include
296#include
297usingnamespacestd;
298
299classCObject;
300classCRuntimeClass
301{
302public:
303char*m_lpszClassName;//对象所属类名
304intm_nObjectSize;//对象大小
305intm_wSchema;//模式号
306CObject*(PASCAL*m_pfnCreateObject)();//构建函数,抽象类为NULL
307CRuntimeClass*m_pBaseClasss;//基类CRuntimeClass对象指针。
308staticCRuntimeClass*pFirstClass;//链表头指针。
static
309CRuntimeClass*m_pNextClass;//下一指针。
310public:
311CObject*CreateObject()
312{
313if(m_pfnCreateObject==NULL)
314{
315cout<<"该类型不支持动态创建!
!
"<316returnNULL;
317}
318CObject*pClass=(*m_pfnCreateObject)();
319returnpClass;
320}
321staticCRuntimeClass*Load()
322{
323cout<<"请输入要动态创建的类名:
";
324strings;
325cin>>s;
326for(CRuntimeClass*pClass=pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
327{
328if(pClass->m_lpszClassName==s)
329{
330returnpClass;
331}
332}
333returnNULL;
334}
335};
336
337classAFX_CLASSINIT
338{
339public:
340AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数
341{
342pNewClass->m_pNextClass=CRuntimeClass:
:
pFirstClass;
343CRuntimeClass:
:
pFirstClass=pNewClass;
344}
345};
346
347/************************************************************************/
348/*动态类型识别宏定义
349//与CRuntimeClass类中的构建函数相区别。
此处的CreateObject函数在每个类中都以static成员函数存在,用以
350//初始化类型型录表,而CRuntimeClass中的CreateObject用于调用每个类的构建函数。
仅仅是函数名相同罢了。
*/
351/************************************************************************/
352
353#defineDECLARE_DYNAMIC(class_name)\
354public:
\
355staticCRuntimeClassClass##class_name;\
356virtualCRuntimeClass*GetRuntimeClass()const;\
357
358
359#defineDECLARE_DYNCREATE(class_name)\
360DECLARE_DYNAMIC(class_name)\
361staticCObject*PASCALCreateObject();\
362
363#defineRUNTIME_CLASS(class_name)\
364(&class_name:
:
Class##class_name)\
365
366#define_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,