C++模拟实现Objective-C动态类型

在OC(Objective-C)里面有动态类型分为以下几类:

-(BOOL)isKindOfClass:classObj        是否是classObj类或其子类

-(BOOL)isMemberOfClass:classObj      是否是classObj的实例 

-(BOOL)respondsTosSelector:selector  类中是否有这个方法 

NSClassFromString(NSString*);        由字符串得到类对象 

NSStringFromClass([类名 Class]);     由类名得到字符串  

Class rectClass= [Rectangle class];  通过类名得到类对象 

Class aClass =[anObject class];      通过实例得到类对象

if([obj1 class]== [obj2 class])      判断是不是相同类的实例

虽然C++本身不包含以上这些功能,但是相比之下C++是更为底层的语言,其实以上大部分也可以用C++模拟实现。虽然这些对实际开发意义或许不大,但是从中我们也可以了解很多高级语言底层知识,从而更深入了解语言本质或者是语言的灵活性。

首先我们来实现isKindOfClass这个函数,该函数在C++主要是判断一个对象是否从一个类的对象或者是某个类的子类对象。我们模拟实现这个功能,假如说A-B-C-D-E一连串的继承,如果满足以下两个条件:1.每个类都有自己的标识,用于通过标识判断对象是否是这个类的对象;2.对于A-B-C-D-E一连串的继承,作出一张链表,用于查询使用。那么如果我们需要判断C c对象是否是A的子类对象时,那么只需要调用一个查询接口,传入A对象标识,当判断是A类的对象时,再查询B对象,然后查询到C对象,此时判断通过于是返回为真。

 1 //在这里我们用类名字作为唯一标识,也就是szClassName变量
 2 //然后向前向后两个链表用于串起整个继承关系
 3 struct ClassRunTimeType
 4 {
 5     char *szClassName;
 6     static ClassRunTimeType* pFirstClass;
 7     ClassRunTimeType *m_pPrevClassRunTimeType;
 8     ClassRunTimeType *m_pNextClassRunTimeType;
 9 };
10
11 //这个类并没有其他用途,唯独借用定义对象时需要执行构造
12 //通过执行构造函数来初始化我们需要第一时间执行的代码
13 //每个类都会用他定义一个对应的对象
14 class CRunTimeType
15 {
16 public:
17     CRunTimeType(ClassRunTimeType *pType);
18 };

有了以上的基本数据结构接下来可以在实际类中动手脚了

 1 class NSObject
 2 {
 3 public:
 4     virtual void ShowHello(){}
 5
 6     BOOL isKindOfClass(ClassRunTimeType *pRunTimeType);
 7     BOOL isMemberOfClass(void *pFun);
 8     void *GetInstallFromName(char *szName);
 9
10     virtual char* GetCurrentClassName()
11     {
12         return NSObject::GetClassName();
13     }
14
15     static char* GetClassName()
16     {
17         return szClassNSObject;
18     }
19 };
20
21 static char szClassNSObject[] = "NSObject";
22 ClassRunTimeType NSObject::classNSObject = {szClassNSObject,NULL,NULL};

szClassName[] = "NSObject"就是这个类的唯一标识,如果要判断是否是出自于这个类,只需要对比这个字符串就可以了,相应的调用方法也很简单,也就是BOOL isKindOfClass(ClassRunTimeType *pRunTimeType)的内部实现。

1 BOOL isKindOfClass(ClassRunTimeType *pRunTimeType)
2 {
3     if (0 == strcmp(GetCurrentClassName(),pRunTimeType->szClassName))
4         return TRUE;
5     return FALSE;
6 }

当然了,这个时候还仅仅只是实现了判断一个对象是不是某个类的对象,对于是不是子类还是不行,因为没有借助上面的链表查询功能。但是相信到了这个具体怎么实现已经不是难事了,如果有疑问可以调本文对应的源码,里面有详细的说明。

可惜的是respondsTosSelector并没有找到很好的方法,首先Object-C每个成员函数都是虚函数,相对很容易实现一些,而C++里面的非虚函数则完全无法判断。其次即使是虚函数,判断起来也存在一定的困难,以VS2010为例,在禁用优化的情况下,调用一个虚函数会执行以下几步:

1 ShowHelloEx.ShowHello();
2 00191080  lea         ecx,[ShowHelloEx]
3 00191083  call        NSObject::ShowHello (191010h)  

首先保存this指针的地址到ecx,这也是VS系列管用手法。其次调用的ShewHello函数内部,但是这里并没有调到虚表里面的对应的地址,而是调到这个地方

1 NSObject::`vcall‘{0}‘:
2 00191140  mov         eax,dword ptr [ecx]
3 00191142  jmp         dword ptr [eax]  

此时再取出虚表地址,然后计算偏移jmp,这时候才是真正虚表的地址,而从函数名获取到的地址只是这里的中转跳转位置也就是191140这个地方。所以说单纯的比较虚表地址来实现这个功能也并不靠谱,换成其他编译器也会存在兼容性问题,所以说这个接口我只能表示无能为力。

NSClassFromString这个函数相对简单,其实很多地方都会用到类似的功能。比如说我们写个程序,在程序上画了一条线,然后保存到文件。如果我们以后要打开这个文件则必须要保存这条线的类名字以及其他特征,读取的时候首先根据类名创建对象,也就是这个函数类似的功能。事实上我们只需要在上面那个结构体中动动手脚就好了,具体实现:

 1 typedef void* ( *pFn)();
 2 //在这里我们用类名字作为唯一标识,也就是szClassName变量
 3 //然后向前向后两个链表用于串起整个继承关系
 4 struct ClassRunTimeType
 5 {
 6     char *szClassName;
 7     static ClassRunTimeType* pFirstClass;
 8     ClassRunTimeType *m_pPrevClassRunTimeType;
 9     ClassRunTimeType *m_pNextClassRunTimeType;
10     pFn pfn;
11 };

pfn这个函数主要用于创建对象,我们只需要在给这个结构体赋值的时候,传入一个函数指针,而函数的目的就是创建对象。首先我们需要遍历我们的链表,寻找到对应的类名,然后调用这个函数创建对象即可。相反,NSStringFromClass也可以用类似的方法实现,具体的可以参考示例代码。

至于判断是否同一个实例就很简单了,首先比较地址对不对,对的话就完全一样^_^其次比较唯一标识,符合的话就是同一个类的对象啦。

DynamicType.zip

时间: 2024-10-13 00:51:02

C++模拟实现Objective-C动态类型的相关文章

Json.net实现方便的Json转C#(dynamic动态类型)对象

以前需要将一段json字符串转换为C#对象时,一般都是定义一个与之对应的实体类来接收.这样做有一个很大的缺点,就是当字符串特别长,属性特别多,又有嵌套时,手敲这个实体类就非常痛苦. 比如之前做的一个接收百度七天天气预报的API,层层嵌套,很痛苦. C# 4.0 之后有了动态类型dynamic.用这个东西配合Json.net可以实现不用定义实体类的json转dynamic类型对象. 以下示例需要先引用Newtonsoft.Json.dll public class Person { public

【转】解析JDK 7的动态类型语言支持

http://www.infoq.com/cn/articles/jdk-dynamically-typed-language Java虚拟机的字节码指令集的数量自从Sun公司的第一款Java虚拟机问世至JDK 7来临之前的十余年时间里,一直没有发生任何变化[1].随着JDK 7的发布,字节码指令集终于迎来了第一位新成员——invokedynamic指令.这条新增加的指令是JDK 7实现“动态类型语言(Dynamically Typed Language)”支持而进行的改进之一,也是为JDK 8

设计模式之工厂模式:模拟DECLARE_DYNAMIC和IMPLEMENT_DYNAMIC动态创建类对象

该形式的工厂模式是我项目中用到的方法,属于很成熟的模版,读者可以直接拿来在自己项目中使用.个人感觉这种方法真正做到了"开放封闭"的原则,最大好处是用户产品类的设计完全不依赖于该模式的实现,比如提供必须的相关函数等.如果不理解工厂模式的话,请参考网上其它文章,本实现在理解上有一点小小的难度.好东西,大家慢慢享用,话不多说,先放代码! 首先是产品基类,它相当于一个接口,产品需要有什么动作就写在这里吧! #ifndef _CPRODUCTBASE_H_ #define _CPRODUCTBA

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

Objective-C具有相当多的动态特性,基本的,也是经常被提到和用到的有 动态类型(Dynamic typing) 动态绑定(Dynamic binding) 动态加载(Dynamic loading) 动态类型:程序直到执行时才能确定所属的类. id 数据类型id 通用的对象类型,可以存储任意类型的对象,id后面没有号,它本身就是个指针类似于void ,但只可以指向对象类型 静态类型与动态类型 编译期检查与运行时检查 静态类型在编译期就能检查出错误 静态类型声明代码可读性好 动态类型只有在

面向对象的JavaScript --- 动态类型语言

面向对象的JavaScript --- 动态类型语言 动态类型语言与面向接口编程 JavaScript 没有提供传统面向对象语言中的类式继承,而是通过原型委托的方式来实现对象与对象之间的继承. JavaScript 也没有在语言层面提供对抽象类和接口的支持. 正因为存在这些跟传统面向对象语言不一致的地方,我们在用设计模式编写代码的时候,更要跟传统面向对象语言加以区别.我们有必要先了解一些 JavaScript 在面向对象方面的知识. 编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一

Python的动态类型

动态类型:                                                      在python中,类型是在运行过程中自动决定的,而不是通过代码声明的. 变量:                                                                                     变量是一个系统表的元素,拥有指向对象的连接的空间 python中,类型的概念是存在于对象中的,而不是变量中,变量是通用的. 变量的使用

OC多态,动态类型绑定

// //  main.m //  OC7类 // //  Created by Zoujie on 15/8/23. //  Copyright (c) 2015年 Zoujie. All rights reserved. // #import <Foundation/Foundation.h> #import "Fraction.h"//导入头文件 #import "Complex.h" #define Choose  0 int main(int 

.net 3.5 c#构建动态类型最佳实践

为什么要在.net3.5下面构建,有几个原因: win7自带.net 3.5 ,用户无须安装 我用的是vs2008,不想升级 .net 4.0引入了关键字,但是我想.net 3.5下面也有类似功能 这是构建orm的基础,一言以蔽之,市面上的orm都不好用,我想重新造轮子 暂时没想到 最终结果是这样的 属性名是字符串,属性值随便什么类型. 下图是我写了两个晚上的orm,多表查询生成的是动态类型List,同时映射到多个实体类,在展现层的代码量极少,便于工具生成. 我对orm的设想如下: 基础的增删改

python学习笔记17(动态类型)

动态类型 在我们接触的对象中,有一类特殊的对象,是用于存储数据的,常见的该类对象包括各种数字,字符串,表,词典.在C语言中,我们称这样一些数据结构为变量,而在Python中,这些是对象. 对象是储存在内存中的实体.但我们并不能直接接触到该对象.我们在程序中写的对象名,只是指向这一对象的引用(reference). 引用和对象分离,是动态类型的核心.引用可以随时指向一个新的对象: a = 3 a = 'python' 第一个语句中,3是储存在内存中的一个整数对象,通过赋值,引用a指向对象3. 第二