MFC方式的动态创建
语言天生就是用来沟通的对象,不免产生碰撞,争论,分歧,演变抑或进化。古人云:有过则改,无则加勉。多发现外物的优点以弥补内心的缺失才是应当所思所学的。
在我窥探到一个对象的创建过程,不,是对象创建前夕MFC所做的工作时(编织一张张天罗地网),被宏精妙的运用手法所震撼。这不是我们常常探讨设计模式的运用场景,MFC的宏可谓是把这点给发扬光大了,让我深刻的体验了一把。下面把自己的所思所学跟同学们分享下,写得不好,大家尽管拍砖:)
创建一个对象A,自然是A *pA = new A;创建B,则B *pB = new B。现在需要动态创建A,B,怎么办?一个简单的办法是给每个class的做个标记(tag),代码内部判断是返回A或B,代码如下:

2 {
3 if(0 == strcmp("A", szTag))
4 {
5 return new A;
6 }
7 else if(0 == strcmp("B", sztag))
8 {
9 return new B;
10 }
11 else
12 {
13 return NULL;
14 }
15 }
上面的代码确实很是easy,给我一个tag就能返回你要对象。立马想到阿基米德的名言:给我一个支点,我就能撬动整个地球:)
如果我们把class的tag和创建它的函数放到同一个struct中,定义如下:
struct RuntimeClass
{
TCHAR *szClassName;
ObjectClass* (*pCreateFn)();
};
然后把这些RuntimeClass 以某种方式串联在一块,会是什么效果呢?呵呵,大概会是这个样子,传进一个tag,只要在这个”串串“(想起成都的麻辣烫阿)中搜一遍,就能返回对应的对象了:)。问题1:怎么串联呢?用stl的容器装起来?看看MFC的源码,原来在RuntimeClass中引入一个自身类型的指针变量,令其指向下一个RuntimeClass,显然,这样可以把n个RuntimeClass组成一个单向的链表,找的时候顺藤摸瓜就行了。窃以为,用stl的容器不是不行,但那样又单单依赖某一容器了。
RuntimeClass的定义摇身变成:
{
TCHAR *szClassName;
RuntimeClass *pBaseClass;
RuntimeClass *pNextClass;
ObjectClass* (*pCreateFn)();
}
又新增了pBaseClass指针,这样要找到当前ObjectClass的基类就方便了。OK,问题2:这些RuntimeClass在什么地方产生并连接起来呢?等代码运行到main里头?呵呵,再来看看MFC的源码,(打开VC6~敲入CObject,Alt+G)
看到老祖宗脚下躺着一个static CRuntimeClass classCObject的成员变量,这意味classCObject在进入main之前应该有所初始化动作,这个初始化动作会是什么呢?如果在class A,B中都安放这样一个static CRuntimeClass的成员变量,上面所说的单向链表中的成员个体不就都有了末,事实上MFC确实也是这样做的。
问题3:这些个static CRuntimeClass该如何连接起来呢?用MFC时我们可不用关心这些啊,呵呵。。。
黎明前的时刻来了,念叨static。。。static,这里需要一个时机,或是一个触发动作,将各个CRuntimeClass连接在一起。能否开辟一个新的static变量,在其的构造函数中完成这个”统一大业“呢?这是否是异想天开?设计如下一个struct:
{
ClassList(RuntimeClass *pNewClass);
};
ClassList::ClassList(RuntimeClass* pNewClass)
{
pNewClass->pNextClass=RuntimeClass::pFirstClass;
RuntimeClass::pFirstClass=pNewClass;
}
这样每当一个ClassList产生时,自动将一个RuntimeClass连接到链表中。故事就讲到这吧,源码已上传,有兴趣的朋友可下载。