现在的位置: 首页 > 综合 > 正文

MFC动态创建(dynamic creation)实现原理

2013年09月01日 ⁄ 综合 ⁄ 共 2549字 ⁄ 字号 评论关闭
文章目录

在用到MFC的文档视图构架你可能有个非常迷惑的地方.就是很多类不知道在哪里就被莫名其妙的实例化了.

以单文档视图为例.代码中你能看到的的实例化的地方就只有两个一个是CWinApp的一个全局变量的实例化,另一个就是
CSingleDocTemplate 实例化.它的构造函数如下

CSingleDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,

CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);

然后接下来的事就你迷惑了,先是继承自SingleDocTemplate的类实例化了继承自CFrameWnd的类和继承自CDocument的类,然后呢继承自CFrameWnd的类又实例化了继承自CView的类.

你可能会想到背后早有写好的代码去实例化这些类了,但是最令你疑惑的是我自己定义继承自啥CView,CDocument等类的类时名字是自己随便取的啊,之前写好的代码竟然能有未卜先知的能力知道这类名? 不然不知道一个类的类名怎么去实例化它啊?

MFC自然没这么神奇的能力.所以毫无疑问的一点是你定义的新类类名信息肯定会传到某个地方,然后在那里实例化该类.背后的机制咋样的呢?

这就是所谓的动态生成(dynamic creation)机制了啊.该机制有用到前面讲的RTTI,在RTTI的基础上再扩充一些功能.

 

动态创建的一个简单例子

1.CRuntimeClass的定义

首先CRuntimeClass定义中除了RTTI信息,添加

struct CRuntimeClass{

CObject* ( *m_pfnCreateObject)(); //函数指针,指向的函数中会通过new实例化一个对象

CObject* CreateObject()

//其他信息省略掉了

}

其中函数CreateObject定义如下

CObject* CRuntimeClass::CreateObject(){

CObject* pObect = NULL;

pObject =(*m_pfnCreateObject)();

}

 

2.宏DECLARE_DYNCEATE

假如定义一个继承自CDocument的类CMyDoc.

我们瞧下CSingleDocTemplate* pTmp = new(.... RUNTIME_CLASS(CMyDoc) ....) //这里忽略其他参数.

CMyDoc是怎么被创建的呢? 先看CMyDoc定义中的宏

 

////////CMyDoc头文件//////

DECLARE_DYNCEATE(CMyDoc)

///////////////////////////////////////////////

相当于:

static CObject* CreateObject();

static CRuntimeClass classCMyDoc;

 

宏定义:

#define DECLARE_DYNCREATE(class_name) \

DECLARE_DYNAMIC(class_name) \

static CObject*  CreateObject();

 

3.宏IMPLEMENT_DYNCREATE

///////////CMyDoc cpp文件/////////////////

IMPLEMENT_DYNCREATE(CMyDoc, CDocument)

/////////////////////////////////////////////////

上面的宏除了前面的RTTI信息外,还有个

CObject*  CMyDoc::CreateObject(){

return new CMyDoc;

}

CMyDoc::classCMyDoc.m_pfnCreateObject = CMyDoc::CreateObject;

 

宏定义:

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \

CObject* class_name::CreateObject() \

{ return new class_name; } \

//IMPLEMENT_RUNTIMECLASS(......)//为讨论方便这里省略掉了

 

4.创建对象

有了上面两个宏,然后CSingleDocTemplate的构造函数中有个参数RUNTIME_CLASS(CMyDoc),我们知道

#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())

的以传的参数实际上是一个指向CMyView中的static CRuntimeClass classCMyDoc的指针.

于是可以这样调用函数创建对象

CObject* pDoc = RUNTIME_CLASS(CMyDoc)->CreateObject();//实际上就是调用

CObject* CMyDoc::CreateObject(){

return new CMyDoc;

}

 

 

总结:

你可能看到上面一堆乱七八糟的东东,就想着真他妈扯蛋啊,搞到最后不就是只需要一个类的名字,然后用该名字来实例化一个类嘛.有必要搞得这么麻烦嘛

该功能说起来简单,但实现起来还真没其他简单方法啊,除非C++语法做些更改,编译器添加些额外支持.我们知道函数中可以随便传个啥参数.

但实例化一个类比如CView* view = new CView; //一个类的名字是不能做为参数的啊.

比如void CreateObject(string className){

className* view = new className;

}

这样的函数绝对无法通过编译的.但我们上面讲到的貌似是这样实现的.因为那是宏,只是简单的文字替换,宏的替换那一步还没有轮到编译器去干活.宏替换完了才是编译器上场.

有了宏可以把类名当"参数"一样用可以说实现了一大半功能了.实际上你如果只是通过前面的两个宏整出一个静态函数static CObject* CreateObject();完全就可以了.但这样显然实现的不够优雅嘛,并且既然有个CRuntimeClass了就干脆把动态创建对象的函数带到该结构体中岂不更好啊(很多地方都用到CRuntimeClass,动态类型识别,动态创建,序列化).

抱歉!评论已关闭.