03 MFC的动态创建

动态创建基本和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; 
}

猜你喜欢

转载自blog.csdn.net/lifeshave/article/details/85316183
03