您的位置:首页 > 其它

动态类型识别&动态创建

2014-05-03 10:33 232 查看
以下大部分内容摘自《windows程序设计 第2版》 王艳平 张铮 编著

动态类型识别:在程序运行过程中,辨别对象是否属于特定类的技术。

应用举例:函数辨别参数类型、需要针对对象的类编写特定的代码。

CRuntimeClass 包含类信息(不仅包含一般的信息,还包括创建类的函数指针)

#include <iostream>
#include<windows.h>
using namespace std;
/////////////////////////////////////////////////////
// 运行期类信息
class CObject;
struct CRuntimeClass
{
// 属性(Attributes)
LPCSTR m_lpszClassName;        // 类的名称
int m_nObjectSize;             // 类的大小
UINT m_wSchema;                // 类的版本号
// 创建类的函数的指针 函数返回值为CObject*类型 调用规则为__stdcall
// 如果你没有显式的说明调用规则的话,编译器会统一按照_cdecl来处理
// c++ 指针:http://hipercomer.blog.51cto.com/4415661/792300
CObject* (__stdcall* m_pfnCreateObject)();
CRuntimeClass* m_pBaseClass;   // 其基类中CRuntimeClass结构的地址

// 操作(operations)
CObject* CreateObject();       //调用m_pfnCreateObject指向的函数
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;

// 内部实现(Implementation)
CRuntimeClass* m_pNextClass;  // 将所有CRuntimeClass对象用简单链表连在一起
};


如果想使所有的类都具有运行期识别和动态创建的特性,那么必须有一个类做为最顶层的类,所有的类都从此类继承。

// CObject 类
class CObject
{
public:
//注意是个虚函数
virtual CRuntimeClass* GetRuntimeClass() const;
virtual ~CObject();

// 属性(Attibutes)
public:
BOOL IsKindOf(const CRuntimeClass* pClass) const;

// 实现(implementation)
public:
static const CRuntimeClass classCObject; //   标识类的静态成员
};


上面是两个类的声明,下面我们看实现:

//CRuntimeClass类实现
inline CObject::~CObject() { }

// 宏定义
// RUNTIME_CLASS宏用来取得class_name类中CRuntimeClass结构的地址
#define RUNTIME_CLASS(class_name) ((CRuntimeClass*)&class_name::class##class_name)

CObject* CRuntimeClass::CreateObject()
{
if(m_pfnCreateObject == NULL)
return NULL;
return (*m_pfnCreateObject)(); // 调用创建类的函数
}

BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const
{
//this指针:  http://blog.csdn.net/ugg/article/details/606396 //this指针作为一个隐含参数传递给非静态成员函数,用以指向该成员函数所属类所定义的对象。
const CRuntimeClass* pClassThis = this;
while(pClassThis != NULL)
{
if(pClassThis == pBaseClass) // 判断标识类的CRuntimeClass的首地址是否相同
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE; // 查找到了继承结构的顶层,没有一个匹配
}

const struct CRuntimeClass CObject::classCObject =
{ "CObject"/*类名*/, sizeof(CObject)/*大小*/, 0xffff/*无版本号*/,
NULL/*不支持动态创建*/, NULL/*没有基类*/, NULL};

CRuntimeClass* CObject::GetRuntimeClass() const
{
// 下面的语句展开后就是“return ((CRuntimeClass*)&(CObject::classCObject));”
return RUNTIME_CLASS(CObject);
}
//CObject类的实现
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
CRuntimeClass* pClassThis = GetRuntimeClass();
return pClassThis->IsDerivedFrom(pClass);
}


动态类型识别举例:

class CPerson : public CObject
{
public:
virtual CRuntimeClass* GetRuntimeClass() const
{ return (CRuntimeClass*)&classCPerson; }

static const CRuntimeClass classCPerson;
};
const CRuntimeClass CPerson::classCPerson =
{ "CPerson", sizeof(CPerson), 0xffff, NULL, (CRuntimeClass*)&CObject::classCObject, NULL };
//   类名        大小      版本号  创建类的函数的指针  基类中CRuntimeClass结构的地址
void main()
{
// 父类指向子类,只能调用两者都有的函数(虚函数)
// 如果父类想调用子类拥有,父类没有的函数是不可以的
// 也就是父类指向子类只能调用子类的虚函数
CObject* pMyObject = new CPerson;

// 判断对象pMyObject是否属于CPerson类或者此类的派生类
if(pMyObject->IsKindOf(RUNTIME_CLASS(CPerson)))
// RUNTIME_CLASS(CPerson)宏被展开后相当于((CRuntimeClass*)&CPerson::classCPerson)
{
CPerson* pMyPerson = (CPerson*)pMyObject;
cout << "a CPerson Object! \n";

// 返回类的信息,要从CRuntimeClass中提取
CRuntimeClass* pClass = pMyObject->GetRuntimeClass();
cout << pClass->m_lpszClassName << "\n";   // 打印出"CPerson"
cout << pClass->m_nObjectSize << "\n";       // 打印出"4" x64为"8"
delete pMyPerson;
}
else
{
delete pMyObject;
}

}


动态创建举例:

//声明
class CPerson : public CObject
{
public:
virtual CRuntimeClass* GetRuntimeClass() const
{ return (CRuntimeClass*)&classCPerson; }

static const CRuntimeClass classCPerson;

static CObject* __stdcall CreateObject()
{ return new CPerson; }
};
//实现
const CRuntimeClass CPerson::classCPerson =
{ "CPerson", sizeof(CPerson), 0xffff, &CPerson::CreateObject/*添加到这里*/, (CRuntimeClass*)&CObject::classCObject, NULL };
//   类名            大小                 版本号      创建类的函数的指针                             基类中CRuntimeClass结构的地址
void main()
{
// 取得CPerson类中CRuntimeClass结构记录的信息
// 在实际应用中,我们一般从磁盘上取得这一信息,
// 从而在代码中没有给出类名的情况下创建该类的对象
CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPerson);

// 取得了pRuntimeClass指针,不用知道类的名字就可以创建该类
CObject* pObject = pRuntimeClass->CreateObject();
if(pObject != NULL && pObject->IsKindOf(RUNTIME_CLASS(CPerson)))
{
cout << "创建成功!\n";
delete pObject;
}
}


MFC对它们进行“优化”,使用了看起来很恶心的宏:

//以下都采用了多行宏定义
// 支持动态类型识别的宏
//声明
#define DECLARE_DYNAMIC(class_name) \
public: \
static const CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const;
//实现
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \
const CRuntimeClass class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
RUNTIME_CLASS(base_class_name), NULL }; \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return RUNTIME_CLASS(class_name); } \
//运行期识别功能只需要类名与基类名即可
#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)

// 支持动态创建的宏
//声明
#define DECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name) \
static CObject* __stdcall CreateObject();
//实现
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
CObject* __stdcall class_name::CreateObject() \
{ return new class_name; } \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
class_name::CreateObject)


动态创建的等价代码:

// 等价代码:

class CPerson : public CObject
{
DECLARE_DYNCREATE(CPerson)      //声明
};
IMPLEMENT_DYNCREATE(CPerson, CObject)  //实现

void main() // main函数里的代码没有变化
{
CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPerson);
CObject* pObject = pRuntimeClass->CreateObject();
if(pObject != NULL && pObject->IsKindOf(RUNTIME_CLASS(CPerson)))
{
cout << " 创建成功!\n";
delete pObject;
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: