MFC抽象类之动态实现技术
前不久,我在北大和哈工大bbs上问了同 一个问题"抽象类能实例化么 not sure",几天后得到大虾的解答,我自己又深入探讨了一些,写下这篇文章以让和我有同样问题的人能从苦恼中解脱出来.
众所周知,含有纯虚函数或者构造函数被声明为protected的类被称之为抽象类
,初学者在教科书上一定得到以下结论:"切记:抽象类不允许实例化".但在实际中
有例外.
//in XX.h
class OBJ
{
protected: OBJ();
//something else
friend OBJ*Createobj();//用static也行,mfc就用的是static
};
//in XX.cpp
OBJ::OBJ()
{cout<<"a obj is being created"<<endl;
}
OBJ*Createobj()
{return new OBJ();}
//in test.cpp
void main()
{
OBJ*ptr=Createobj();
delete ptr;
}
run后结果如下:
a obj is being created
Press any key to continue
看来是实例成功了,当然这个例子离动态创建还有区别,下面让我们看一看MFC是如何来进行动态创建的(不知你是否发现,在MFC的SDI和MDI程序中,都是用了动态创建机制,只是他使用了一些宏和CRuntimeClass这各类帮忙)
侯捷的"深入浅出MFC"中又很详细的关于这方面的讲解,不过他没有提到微软实现这种做法的目的之一是抽象类实例化的实现.
其实现过程大致如下:MFC利用一些宏DECLARE_DYNCREATE,IMPLEMENT_DYNCREATE将一些主要的东西悄悄的插入到将具有动态生成的类中,我们以SDI的CMainFrame的动态生成为例,看一看CMainFrame的声明文件,他的constuctor可是protected的呦,DECLARE_DYNCREATE在MainFrm.h中加了几个重要的函数,其中对动态创建至关重要的是
static CObject*PASCAL CreateObject();//他可是用来调用CMainFrame
static const AFX_DATA CRuntimeClass classCMainFrame; 的constuctor
看看他的实现:
CObject*PASCAL CreateObject()
{ return new CMainFrame;}
但是我们在源代码中好像看不到谁调用了这个函数,事实上微软很秘密的 把他转移给了CRuntimeClass结构
看看CRuntimeClass结构
struct CRuntimeClass
{
// Attributes
//somethingelse
CObject* (PASCAL* m_pfnCreateObject)();
//.....
// Operations
CObject* CreateObject();
//...........
};
这里我仅列出两个与动态创建有关的成员.
IMPLEMENT_DYNCREATE宏完成了CMainFrame类中CRuntimeClass classCMainFrame的初始化工作,看下面代码
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) CObject* PASCAL class_name::CreateObject() { return new class_name; } IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, class_name::CreateObject)
m_pfnCreateObject被赋值为CMainFrame::CreateObject,看出点门道了吧^_^.
再看看CObject* CRuntimeClass::CreateObject()的实现吧.
CObject* CRuntimeClass::CreateObject()
{
.........
return (*m_pfnCreateObject)();
}
也许你还是很糊涂,但不知道你了不了解SDI程序的启动过程,它启动时默认打开一个单文档文件,其调用顺序如下:
CWinapp::OnFileNew()--->CSingleDocTemplate::OpenDocumentFile()-->...CDocTemplate::CreateNewFrame()
而CDocTemplate::CreateNewFrame()的实现如下:
CDocTemplate::CreateNewFrame()
{//......
CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();
//....
}
其中m_pFrameClass是指向CMainFrame成员CRuntimeClass classCMainFrame的指针,
下面从后到前捋清一下思路:
m_pFrameClass->CreateObject()返回(*m_pfnCreateObject)(),而后者指向的是static CMainFrame::CObject*PASCAL CreateObject();
现在一切都很清晰了.