动态类型识别&动态创建
以下大部分内容摘自《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;
}
}
动态类型识别&动态创建的更多相关文章
- iOS-------- Objective-C多态:动态类型识别+动态绑定+动态加载
一.Objective-C多态 1.概念:相同接口,不同的实现 来自不同类可以定义共享相同名称的方法. 动态类型能使程序直到执行时才确定对象所属类型 动态类型绑定能使程序直到执行时才确定要对对象调用的 ...
- Objective-C多态:动态类型识别+动态绑定+动态加载
http://blog.csdn.net/tskyfree/article/details/7984887 一.Objective-C多态 1.概念:相同接口,不同的实现 来自不同类可以定义共享相同名 ...
- C++基础知识:动态类型识别
1.动态类型指的是基类指针所指向的对象的实际类型 2.C++中的多态根据实际的对象类型调用对应的虚函数(1)可以在基类中定义虚函数返回具体的类型信息(2)所有的派生类都必须实现类型相关的虚函数(3)每 ...
- OC 动态类型,动态绑定,动态加载
OC 动态类型,动态绑定,动态加载 Objective-C具有相当多的动态特性,基本的,也是经常被提到和用到的有 动态类型(Dynamic typing) 动态绑定(Dynamic binding) ...
- C# 动态类型与动态编译简介
关于C#的动态类型与动态编译的简介,主要是一个Demo. 动态类型 关键字: dynamic 这里有详细的介绍:[C#基础知识系列]专题十七:深入理解动态类型 动态类型的应用场景 可以减少强制转换(强 ...
- 《精通C#》第十六章-动态类型和动态语言运行时-第一节至第四节
在.Net4.0中引入了一个关键字dynamic,这是一个动态类型关键字.Net中还有一个关键字是var,这是一个隐式类型,可以定义本地变量,此时var所代表的实际的数据类型有编译器在初次分配时决定, ...
- C# 4.0中的动态类型和动态编程
# 4.0的主题就是动态编程(Dynamic Programming).虽然C#仍然是一种静态语言,但是对象的意义开始变得越来越“动态”.它们的结构和行为无法通过静态类型来捕获,或者至少编译器在编译程 ...
- OC 动态类型和静态类型
多态 允许不同的类定义相同的方法 动态类型 程序直到执行时才能确定所属的类 静态类型 将一个变量定义为特定类的对象时,使用的是静态形态 将一个变量定义为特定类的对象时,使用的是静态类型,在编译的时候就 ...
- C# 匿名对象(匿名类型)、var、动态类型 dynamic
本文是要写的下篇<C#反射及优化用法>的前奏,不能算是下一篇文章的基础的基础吧,有兴趣的朋友可以关注一下. 随着C#的发展,该语音内容不断丰富,开发变得更加方便快捷,C# 的锋利尽显无疑. ...
随机推荐
- 基于 Annotation 的装配(注解)
注解:就是一个类,使用@注解名称 开发中:使用注解 取代 xml配置文件. 1. @Component取代<bean class=""> @Component(&quo ...
- C++ 根据日期判断星期几
int CaculateWeekDay(int y,int m, int d) { ||m==) { m+=; y--; } *m+*(m+)/+y+y/-y/+y/)%; ; }
- arduino中的serial .available()和serial.read()
Serial.available() 的意思是:返回串口缓冲区中当前剩余的字符个数.一般用这个函数来判断串口的缓冲区有无数据,当Serial.available()>0时,说明串口接收到了数据, ...
- 九十七、SAP中ALV事件之十,通过REUSE_ALV_COMMENTARY_WRITE函数来显示ALV的标题
一.SE37查看REUSE_ALV_COMMENTARY_WRITE函数 二.查看一下导入 三.我们点击SLIS_T_LISTHEADER,来看一下类型 四.我们再看一下,这个info是60长度的字符 ...
- 042-PHP使用闭包函数递归无限级分类
<?php //使用闭包函数递归无限级分类 function demo($array){ # 用于存储递归后的队列 $data = []; # 递归函数 $func = function (&a ...
- 前端安全之 XSS攻击
参看: XSS的原理分析与解剖 前端安全 -- XSS攻击 web大前端开发中一些常见的安全性问题 1.前言 XSS 是面试时,hr提出来给我的,然后大体的浏览一遍,今天才查阅资料大体了解了它. XS ...
- 与Power BI一起使用Cortana
使用此页面测试您的Cortana卡.https://app.powerbi.com/cortana/test 文档: 使用Power BI为Cortana创建自定义答案页https://powerbi ...
- 第一篇web框架
第一篇web框架 http协议 web应用和web框架 主 文 http协议 HTTP简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维 ...
- 代码化UI设计
最近在阅读Qt 5.9 C++开发指南,为了加深对书本上内容的理解,参照书上的讲解尝试写了一些demo,用于以后工作中查阅,如果涉及侵权请告知,实例程序samp2_3 mydialog.h #ifnd ...
- npm - 换淘宝源
npm - 换淘宝源Node 的模块管理器 npm 会一起安装好.由于 Node 的官方模块仓库网速太慢,模块仓库需要切换到阿里的源. $ npm config set registry https: ...