深入浅出MFC学习笔记第三章MFC六大关键技术之仿真类型识别动态创建.docx
- 文档编号:30049609
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:31
- 大小:22.98KB
深入浅出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
294 18px;">#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,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 深入浅出 MFC 学习 笔记 第三 六大 关键技术 仿真 类型 识别 动态 创建