以下大部分内容摘自《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;
}
}

动态类型识别&动态创建的更多相关文章

  1. iOS-------- Objective-C多态:动态类型识别+动态绑定+动态加载

    一.Objective-C多态 1.概念:相同接口,不同的实现 来自不同类可以定义共享相同名称的方法. 动态类型能使程序直到执行时才确定对象所属类型 动态类型绑定能使程序直到执行时才确定要对对象调用的 ...

  2. Objective-C多态:动态类型识别+动态绑定+动态加载

    http://blog.csdn.net/tskyfree/article/details/7984887 一.Objective-C多态 1.概念:相同接口,不同的实现 来自不同类可以定义共享相同名 ...

  3. C++基础知识:动态类型识别

    1.动态类型指的是基类指针所指向的对象的实际类型 2.C++中的多态根据实际的对象类型调用对应的虚函数(1)可以在基类中定义虚函数返回具体的类型信息(2)所有的派生类都必须实现类型相关的虚函数(3)每 ...

  4. OC 动态类型,动态绑定,动态加载

    OC 动态类型,动态绑定,动态加载 Objective-C具有相当多的动态特性,基本的,也是经常被提到和用到的有 动态类型(Dynamic typing) 动态绑定(Dynamic binding) ...

  5. C# 动态类型与动态编译简介

    关于C#的动态类型与动态编译的简介,主要是一个Demo. 动态类型 关键字: dynamic 这里有详细的介绍:[C#基础知识系列]专题十七:深入理解动态类型 动态类型的应用场景 可以减少强制转换(强 ...

  6. 《精通C#》第十六章-动态类型和动态语言运行时-第一节至第四节

    在.Net4.0中引入了一个关键字dynamic,这是一个动态类型关键字.Net中还有一个关键字是var,这是一个隐式类型,可以定义本地变量,此时var所代表的实际的数据类型有编译器在初次分配时决定, ...

  7. C# 4.0中的动态类型和动态编程

    # 4.0的主题就是动态编程(Dynamic Programming).虽然C#仍然是一种静态语言,但是对象的意义开始变得越来越“动态”.它们的结构和行为无法通过静态类型来捕获,或者至少编译器在编译程 ...

  8. OC 动态类型和静态类型

    多态 允许不同的类定义相同的方法 动态类型 程序直到执行时才能确定所属的类 静态类型 将一个变量定义为特定类的对象时,使用的是静态形态 将一个变量定义为特定类的对象时,使用的是静态类型,在编译的时候就 ...

  9. C# 匿名对象(匿名类型)、var、动态类型 dynamic

    本文是要写的下篇<C#反射及优化用法>的前奏,不能算是下一篇文章的基础的基础吧,有兴趣的朋友可以关注一下. 随着C#的发展,该语音内容不断丰富,开发变得更加方便快捷,C# 的锋利尽显无疑. ...

随机推荐

  1. gerrit 版本下载

    链接:https://gerrit-releases.storage.googleapis.com 如下载gerrit-2.12.2.war https://gerrit-releases.stora ...

  2. springboot#interceptor

    _ 拦截器相对与过滤器Filter 而言,拦截器是spring中的概念.过滤器是servlet中的概念.在spring中肯定是优先使用拦截器Interceptor的. public class My1 ...

  3. spark-submit脚本分析

    执行任务 ./spark-submit \ --class cn.com.dtmobile.spark.DebugTest \ --master yarn \ --deploy-mode client ...

  4. ROS2学习日志:QoS学习日志

    QoS学习日志 参考:ROS2API 及 https://index.ros.org/doc/ros2/Concepts/About-Quality-of-Service-Settings 1.概述 ...

  5. java 学生信息管理

    题目: 一.测试要求:      1.按照测试内容要求完成程序的设计与编程:      2.将最终结果的源文件(.java)文件上传到以班级为单位,保存源程序.      3.建立学号姓名文件夹,如: ...

  6. HDU - 4430 Yukari's Birthday(二分+枚举)

    题意:已知有n个蜡烛,过生日在蛋糕上摆蜡烛,将蜡烛围成同心圆,每圈个数为ki,蛋糕中心最多可摆一个蜡烛,求圈数r和看,条件为r*k尽可能小的情况下,r尽可能小. 分析:n最大为1012,k最少为2,假 ...

  7. HDU - 5898 odd-even number (数位dp)

    题意:求一个区间内,满足连续的奇数长度是偶数,连续的偶数长度是奇数的数的个数. #include<cstdio> #include<cstring> #include<c ...

  8. Vue点击按钮下载对应图片

    最近有用到点击某个按钮 自动下载对应图片,可是对于浏览器不同的问题,会有‘个别’浏览器出现不能下载的或者下载的效果不同等的问题, 可以直接用创建canvas方法: 定义图片地址Img: "w ...

  9. 简单看看LongAccumulator

    上篇博客我们看了AtomicLong和LongAdder的由来,但是有的时候我们想一下,LongAdder这个类也有点局限性,因为只能是每一次都+1,那有没有办法每次+2呢?或者每次乘以2?说得更抽象 ...

  10. C#高级编程(第9版) 第08章 委托、lambda表达式和事件 笔记

          本章代码分为以下几个主要的示例文件: 1. 简单委托 2. 冒泡排序 3. lambda表达式 4. 事件示例 5. 弱事件     引用方法 委托是寻址方法的.NET版本.在C++中函数 ...