动态创建基本和C++的new云算符创建没有区别,但是回避了C++语言中不让执行如下对象创建的情形:
char *className = “MyClass”;
CObject *obj = new className;
那MFC动态创建怎么用呢?这次我们直接思路同上篇一样,代码直接贴宏展开后的代码,上面带注释,使用只需将展开代码注释后,将宏解注释就是同样的效果。
/*
*HelloMFC.h
*/
#ifndef _HELLO_MFC_
#define _HELLO_MFC_
class CMyApp : public CWinApp{
public:
virtual BOOL InitInstance();
};
class CMainWindow : public CFrameWnd{
//DECLARE_DYNCREATE(CMainWindow)//此宏展开为下面的语句
public:
static const CRuntimeClass classCMainWindow;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
public:
CMainWindow();
};
#endif
/*
*HelloMFC.cpp
*/
#include <afxwin.h>
#include "HelloMFC.h"
CMyApp myApp;
BOOL CMyApp::InitInstance()
{
//m_pMainWnd = (CMainWindow*)RUNTIME_CLASS(CMainWindow)->CreateObject();//展开为下面语句
m_pMainWnd = (CMainWindow*)((CRuntimeClass*)(&CMainWindow::classCMainWindow))->CreateObject();
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
//IMPLEMENT_DYNCREATE(CMainWindow, CFrameWnd) //展开为下面语句
CObject* PASCAL CMainWindow::CreateObject()
{
return new CMainWindow;
}
//IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, class_name::CreateObject, NULL)
const CRuntimeClass CMainWindow::classCMainWindow = {
"CMainWindow", sizeof(class CMainWindow), 0xFFFF, CMainWindow::CreateObject,
((CRuntimeClass*)(&CFrameWnd::classCFrameWnd)), NULL
};
CRuntimeClass* CMainWindow::GetRuntimeClass() const
{
return ((CRuntimeClass*)(&CMainWindow::classCMainWindow));
}
CMainWindow::CMainWindow()
{
Create(NULL, TEXT("Hello MFC"));
}
那么问题来了,这玩意怎么实现的,现在我们得回过头来再看看上篇那个类了!下面贴代码加注释:
struct CRuntimeClass
{
LPCSTR m_lpszClassName; //指向类名的指针
int m_nObjectSize; //对象大小
UINT m_wSchema; //这个宏定义填的默认值先不管他
CObject* (PASCAL* m_pfnCreateObject)(); // 关键点来了,函数指针,这就是用来保存我们上面CreateObject函数地址的指针
#ifdef _AFXDLL //条件编译,动态链接库时使用
CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
#else
CRuntimeClass* m_pBaseClass; //我们选择的静态链接库使用这个来指向父类
#endif
CObject* CreateObject();
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
// dynamic name lookup and creation
static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);
// 先不去管
void Store(CArchive& ar) const;
static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
// 用单链表来连接运行时类对象
CRuntimeClass* m_pNextClass; // 连接已经注册的类
const AFX_CLASSINIT* m_pClassInit;//默认NULL,先不管吧
};
接下来我们在上面贴的示例代码此处下断点:
然后F11跟进去来到下面代码出,下面贴出代码注释写一下:
CObject* CRuntimeClass::CreateObject()
{
ENSURE(this);//用来抛出异常的,感兴趣可以跟进去看下
if (m_pfnCreateObject == NULL)//函数指针判断
{
TRACE(traceAppMsg, 0,
_T("Error: Trying to create object which is not ")
_T("DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n"),
m_lpszClassName);
return NULL;
}
CObject* pObject = NULL;
TRY //自行跟一下咯,异常处理
{
pObject = (*m_pfnCreateObject)();//调用了我们的CreateObject函数
}
END_TRY
return pObject;
}
说了那么多,我们通过名字来创建对象的问题还没有解决啊!这时,我们应该想想上篇我们说运行程序前跟我们创建了一个继承链表,这点向同了,那么我们就来贴下面代码咯!
/*
*HelloMFC.h
*/
#ifndef _HELLO_MFC_
#define _HELLO_MFC_
#include <iostream>
class CMyApp : public CWinApp{
public:
virtual BOOL InitInstance();
};
class CMainWindow : public CFrameWnd{
//DECLARE_DYNCREATE(CMainWindow)//此宏展开为下面的语句
public:
static const CRuntimeClass classCMainWindow;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
//通过名字来创建对象
static CObject* CreateObjectByName(const char *pClassName);
static CRuntimeClass* FromName(const char *pClassName);
public:
CMainWindow();
};
#endif
/*
*HelloMFC.h
*/
#ifndef _HELLO_MFC_
#define _HELLO_MFC_
#include <iostream>
class CMyApp : public CWinApp{
public:
virtual BOOL InitInstance();
};
class CMainWindow : public CFrameWnd{
//DECLARE_DYNCREATE(CMainWindow)//此宏展开为下面的语句
public:
static const CRuntimeClass classCMainWindow;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
//通过名字来创建对象
static CObject* CreateObjectByName(const char *pClassName);
static CRuntimeClass* FromName(const char *pClassName);
public:
CMainWindow();
};
#endif
/*
*HelloMFC.cpp
*/
#include <afxwin.h>
#include "HelloMFC.h"
CMyApp myApp;
BOOL CMyApp::InitInstance()
{
m_pMainWnd = (CMainWindow*)CMainWindow::CreateObjectByName("CMainWindow");//通过类名来创建对象
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
//IMPLEMENT_DYNCREATE(CMainWindow, CFrameWnd) //展开为下面语句
CObject* PASCAL CMainWindow::CreateObject()
{
return new CMainWindow;
}
//IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, class_name::CreateObject, NULL)
const CRuntimeClass CMainWindow::classCMainWindow = {
"CMainWindow", sizeof(class CMainWindow), 0xFFFF, CMainWindow::CreateObject,
((CRuntimeClass*)(&CFrameWnd::classCFrameWnd)), NULL
};
CRuntimeClass* CMainWindow::GetRuntimeClass() const
{
return ((CRuntimeClass*)(&CMainWindow::classCMainWindow));
}
CMainWindow::CMainWindow()
{
Create(NULL, TEXT("Hello MFC"));
}
CObject* CMainWindow::CreateObjectByName(const char *pClassName)
{
if (pClassName == nullptr){
return nullptr;
}
CRuntimeClass* pClass = FromName(pClassName);
if (pClass == nullptr){
return nullptr;
}
CObject* pObject = pClass->CreateObject();
return pObject;
}
CRuntimeClass* CMainWindow::FromName(const char *pClassName)
{
if (pClassName == nullptr){
return nullptr;
}
CRuntimeClass* pClass = NULL;
for (pClass = (CRuntimeClass*)(&CMainWindow::classCMainWindow); pClass != NULL; pClass = pClass->m_pBaseClass){
if (lstrcmpA(pClassName, pClass->m_lpszClassName) == 0){
return pClass;
}
}
return NULL;
}