1、深入浅出MFC学习笔记第三章MFC六大关键技术之仿真类型识别动态创建第三章:MFC六大关键技术之仿真:类型识别 深入理解MFC的内部运行原理,是本次学习深入浅出MFC的主要目的。要模仿的六大技术包括:1:MFC程序的初始化过程。2:RTTI(Runtime type identification)运行时类型识别。3:Dynamic creation 动态创建4:Persistence永久保存5:消息映射6:消息传递。RTTI(运行时类型识别) IsKindOf能够侦测某个对象是否属于某种类。即判断某一对象所属的类是否是父类或当前类; 要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信
2、息,这被称为类型型录表。MFC以链表的方式建立了此表。 类型型录表的每个元素为CRuntimeClass类型,其定义为:cpp view plaincopy1 class CRuntimeClass 2 3 4 5 public: 6 7 LPCSTR m_lpszClassName;/对象所属类名 8 9 Int m_nObjectSize;/对象大小 10 11 UINT m_wSchema;/模式号 12 13 CObject *(PASCAL*m_pfnCreateObject)();/构建函数抽象类为NULL 14 15 CRuntimeClass *pBaseClasss;/基类C
3、RuntimeClass对象指针。 16 17 Static CRuntimeClass *pFirstClass;/链表头指针。 18 19 CRuntimeClass *m_pNextClass;/下一指针。 20 21 ; MFC使用此类作为每个类的成员变量。使用宏定义为每个类定义了自己的CRuntimeClass成员变量。DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏使用这两个宏将CRuntimeClass对象不知不觉放到类之中。DECLARE_DYNMIC宏定义如下:cpp view plaincopy22 #define DELCARE_DYNMIC ( cl
4、ass_name ) 23 24 public: 25 26 static CRuntimeClass class#class_name 27 28 virtual CRuntimeClass *GetRuntimeClass()const; #用来告诉编译器把两个字符串连接起来。如果使用这个宏:DELCARE_DYNMIC(CView);那么预编译器将生成下列代码:cpp view plaincopy29 public: 30 31 static CRuntimeClass classCView; 32 33 virtual CRuntimeClass*GetRuntimeClass()co
5、nst; 以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。cpp view plaincopy34 #define IMPLEMENT_DYNMIC (class_name,base_class_name) 35 36 _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NU
6、LL); 37 38 _IMPLEMENT_RUNTIMECLASS又是一个宏,它定义如下: 39 40 #define _IMPLEMENT_RUNTIMECLASS(class_name, 41 42 base_class_name,wSchema,pfnNew) 43 44 static char _lpsz#class_name=#class_name; 45 46 CRuntimeClass class_name:class#class_name= 47 48 _lpsz#class_name,sizeof(class_name), 49 50 wSchema,pfnNew, 51
7、52 RUNTIME_CLASS(base_class_name),NULL 53 54 ; 55 56 static AFX_CLASSINIT _init#class_name 57 58 ( & class_name:class#class_name); 59 60 CRuntimeClass *class_name:GetRuntimeClass()const 61 62 63 64 return &class_name:class#classname; 65 66 67 68 #define RUNTIME_CLASS(class_name) 69 70 ( &class_name:
8、class#class_name); AFX_CLASSINIT是一个类,看着跟宏定义似的,这样做很容易让人迷惑。它用于将本节点连接到类型型录表,定义如下:cpp view plaincopy71 class AFX_CLASSINIT 72 73 74 75 public: 76 77 AFX_CLASSINIT(CRuntimeClass*pNewClass)/构造函数 78 79 80 81 pNewClass-m_pNextClass=CRuntime:pFirstClass; 82 83 CRuntimeClass:pFirstClass =pNewClass; 84 85 86 8
9、7 ; 用法:cpp view plaincopy88 class CWnd:public CCmdTarget 89 90 91 92 public: 93 94 DECLARE_DYNAMIC(CWnd); 95 96 97 ; IMPLEMENT_DYNMIC(CWnd,CCmdTarget);代码展开后为;cpp view plaincopy98 class CWnd:public CCmdTarget 99 100 101 102 public: 103 104 static CRuntimeClass classCView; 105 106 virtual CRuntimeClas
10、s*GetRuntimeClass()const 107 108 109 110 ; 111 112 113 114 static char _lpszCWnd=CWnd; 115 116 CRuntimeClass CWnd:classCWnd= 117 118 119 120 _lpszCView , sizeof(CWnd) , FFFF,NULL , &Wnd:classCWnd , NULL); 121 122 ; 123 124 static AFX_CLASSINIT _init_CWnd(&CWnd:classCWnd); 125 126 127 128 Return &CWn
11、d:classCWnd; 129 130 定义宏的过程很复杂,但是一旦定义好之后,在使用时仅仅两句话就可以完成定义CRuntimeClass对象并且连接类型型录链表的工作。CObject是所有类的基类,也是链表的头,此类应特别定义,不能在CObject内使用定义好的宏。cpp view plaincopy131 class CObject 132 133 134 135 public: 136 137 virtual CRuntimeClass*GetRuntimeClass()const; 138 139 static CRuntimeClass classCObject; 140 141
12、; 142 143 static char szCobject=CObject; 144 145 struct CRuntimeClass CObject:classCObject= 146 147 148 149 szCObject ,sizeof(CObject),0xFFFF,NULL,NULL,NULL 150 151 ; 152 153 static AFX_CLASSINIT _init_CObject(&Cobject:classObject); 154 155 CRuntimeClass *CObject:GetRuntimeClass()const 156 157 158 1
13、59 return &CObject:classCObject; 160 161 由于CRuntimeClass对象是static成员变量,因此需要在类外初始化。如果忘记初始化将会报链接错误。CRuntimeClass*CRuntimeClass:pFirstClass=NULL;建好了类类型路表,要实现IsKindOf功能很容易。首先在CObject加上一个IsKindOf函数,于是所有继承自此类的类都具有类型识别的功能。能够将某个CRuntimeClass对象与类类型型录中的元素进行比较。如: cpp view plaincopy162 class CObject 163 164 165
14、166 public: 167 168 bool IsKindOf(const CRuntimeClass*pClass)const 169 170 171 172 CRuntimeClass *pClassThis=GetRuntimeClass(); 173 174 while(pClassThis) 175 176 177 178 if(pClassThis=pClass) 179 180 return true; 181 182 pClassThis=pClassThis-m_pBaseClass;/沿着基类寻找。 183 184 185 186 return false; 187 1
15、88 189 190 ; 如果我们调用CWnd *cw=new CWnd; cw-IsKindOf(RUNTIME_CLASS(CFrameWnd); RUNTIME_CLASS实际就是&CFrameWnd:classCFrameWnd,它就是CFrameWnd的static的CRuntimeClass类型成员。函数内利用GetRuntimeClass取得本类的CRuntimeClass对象的地址,即&CWnd:classCWnd,然后进行比较。因为每一类型共用一个static的CRuntimeClass对象,因此属于同于类的CRuntimeClass对象的地址相同。动态创建 每一类的构建函数
16、可以记录在类型别录中,当获得一个类名称,通过查找类别型录表找出对应的元素,然后调用其构建函数产生新对象。 在CRuntimeClass中m_pfnCreateObject即为构建函数首地址。为了实现动态创建,需要添加两个宏:DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE。如:cpp view plaincopy191 #define DECLARE_DYNCREATE(class_name) 192 193 DECLARE_DYNCREATE(class_name) 194 195 static CObject *PASCAL CreateObject(); 196
17、 197 #define IMPLEMENT_DYNCREATE (class_name,base_class_name) 198 199 CObject*PASCAL class_name:CreateObject() 200 201 return new classname; 202 203 _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name, 204 205 0xFFFF,class_name:CreateObject) 以CFrameWnd为例,下列程序代码:cpp view plaincopy206 class CFrameWnd:p
18、ublic CWnd 207 208 209 210 public: 211 212 DECLEARE_DYNCREATE(CFrameWnd); 213 214 ; IMPLEMENT_DYNCREATE(CFrameWnd,CWnd);展开如下: cpp view plaincopy215 class CFrame:public CWnd 216 217 218 219 public: 220 221 static CRuntimeClass classCFrameWnd; 222 223 virtual CRuntimeClass *GetRuntimeClass()const; 224
19、 225 static CObject *PASCAL CreateObject(); 226 227 ; 228 229 CObject _PASCAL CFrameWnd:CreateObject() 230 231 232 233 return new CFrameWnd; 234 235 236 static char _lpszCFrameWnd=CFrameWnd; 237 238 CRuntimeClass CFrameClass:classCFrameWnd= 239 240 _lpszCFrameWnd,sizeof(CFrameWnd),0xFFFF,CFrameWnd:C
20、reateObject,RUNTIME_CALSS(CWnd),NULL; 241 242 static AFX_CLASSINIT _init_CFrameWnd 243 244 (&CFrameWnd:classCFrameWnd); 245 246 CRuntimeClass*CFrameWnd:GetRunimeClass()const 247 248 return &CFrameWnd:classCFrameWnd; 注意对象构建函数为static函数。为了支持动态创建需要在CRuntimeClass内添加两个函数:CreateObject和CRuntimeClass:Load成员函
21、数。cpp view plaincopy249 CObject *CRuntimeClass:CreateObject() 250 251 252 253 If(m_pfnCreateObject=NULL)/不支持动态创建。 254 255 256 257 throw runtime_error(此类不支持动态创建); 258 259 Return NULL; 260 261 262 263 CObject*pObject=(*m_pfnCreateObject)(); 264 265 Return pObject; 266 267 268 269 CRuntimeClass*PASCL C
22、RuntimeClass:Load() 270 271 272 273 Char szClassName64; 274 275 CRuntimeClass*pClass 276 277 coutszClassName; 280 281 for(pClass=pFirstClass;pClass;pClass=pClass-m_pNextClass) 282 283 284 285 if(strcmp(szClassName,pClass-m_lpszClassName)=0) 286 287 return pClass; 288 289 return NULL; 290 291 292 293
23、 以下为类型识别及动态创建的完整代码:cpp view plaincopy294 #include 295 #include 296 #include 297 using namespace std; 298 299 class CObject; 300 class CRuntimeClass 301 302 public: 303 char* m_lpszClassName;/对象所属类名 304 int m_nObjectSize;/对象大小 305 int m_wSchema;/模式号 306 CObject*(PASCAL*m_pfnCreateObject)();/构建函数,抽象类为
24、NULL 307 CRuntimeClass *m_pBaseClasss;/基类CRuntimeClass对象指针。 308 static CRuntimeClass *pFirstClass;/链表头指针。static 309 CRuntimeClass *m_pNextClass;/下一指针。 310 public: 311 CObject*CreateObject() 312 313 if(m_pfnCreateObject=NULL) 314 315 cout该类型不支持动态创建!endl; 316 return NULL; 317 318 CObject*pClass=(*m_pf
25、nCreateObject)(); 319 return pClass; 320 321 static CRuntimeClass*Load() 322 323 couts; 326 for(CRuntimeClass*pClass=pFirstClass;pClass;pClass=pClass-m_pBaseClasss) 327 328 if(pClass-m_lpszClassName=s) 329 330 return pClass; 331 332 333 return NULL; 334 335 ; 336 337 class AFX_CLASSINIT 338 339 publ
26、ic: 340 AFX_CLASSINIT(CRuntimeClass*pNewClass)/构造函数 341 342 pNewClass-m_pNextClass=CRuntimeClass:pFirstClass; 343 CRuntimeClass:pFirstClass =pNewClass; 344 345 ; 346 347 /*/ 348 /* 动态类型识别宏定义 349 /与CRuntimeClass类中的构建函数相区别。此处的CreateObject函数在每个类中都以static成员函数存在,用以 350 /初始化类型型录表,而CRuntimeClass中的CreateObj
27、ect用于调用每个类的构建函数。仅仅是函数名相同罢了。*/ 351 /*/ 352 353 #define DECLARE_DYNAMIC(class_name) 354 public: 355 static CRuntimeClass Class#class_name; 356 virtual CRuntimeClass*GetRuntimeClass()const; 357 358 359 #define DECLARE_DYNCREATE(class_name) 360 DECLARE_DYNAMIC(class_name) 361 static CObject*PASCAL CreateObject(); 362 363 #define RUNTIME_CLASS(class_name) 364 (&class_name:Class#class_name) 365 366 #define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1