目录
RTTI机制的原理
RTTI全称是Run-Time Type Identification,代表运行时类型识别。一般而言,面向对象编程语言都会支持它,只是支持的形式不太一样。RTTI一般包括类名称、类方法列表、虚函数表、父类子类关系等。一般而言,编译器会生成对应类的相关讯息,并让创建的对象指向相应的讯息,保存在内存中。在运行期,调用RTTI相应的运算符时会自动调用到编译器生成和指向的讯息。C++98标准引入RTTI,dynamic_cast/type_info/typeid都是RTTI的一部分。
- RTTI机制在越高级语言使用范围越广,因为它们有完善的运行时支持。例如,C#/JS/Python/Java/Swift等,可以利用反射获取类型信息。
- C语言不支持RTTI,如需要,可以手动增加结构体"信息"成员和指针,保存变量类型字符串和关联。
- ObjC有一套较为现代化的运行时,例如,[oneObject class]获取Class类信息,NSStringFromClass(oneClass)返回类对应的字符串。
- C++ RTTI机制被加入语言标准,是因为当时很多语言编译器实现商都有各自的RTTI机制,造成了各家不兼容,后来被标准化。
不同语言类型转换的底层原理
编程语言中必然有很多情况需要转换类型。比如引入const的概念就为了提高安全性,编译器提前检查,避免一些意外修改。当然,有时,我们希望手动转换一个变量的类型,让其变成常量,可以利用编译器提供的cast方法。
- C++早期提供了const_cast,写法繁琐,C++17引入std::as_const写法更轻松,C++20引入bit_cast可实现位级别复制,而非普通float和int转换后丢失小数位的问题。
隐式转换和强制转换
编译器为了简化不同类型变量互操作,引入隐式转换,可以安全转换(不损失数据)数据,此过程由编译器自动完成。当不满足如上条件,需要程序员手动用强制类型转换。
- C/ObjC/C++ 语言大小小于int的整型(包括char和枚举)的类型使用时都自动转换成int. 有人有疑问,这样不是占用空间变大吗?事实上,仅仅是使用时,数据保存依然按对应类型。为什么使用时要转换成int呢?因为CPU操作int最自然,换成char或short一样会使用int大小的寄存器,没好处。下图push eax保存字符c,并传递给printf做参数。
- Swift 是一门相对安全的语言,没有隐式类型转换。
父类子类转换
子类本身就是父类的一种,转换成父类很自然,但父类转换成子类就需要考虑对不对。
- C++提供dynamic_cast主要为了继承体系转换,比static_cast更智能。虽然C++支持强制转换,必要时也可以通过typeid判断类型是否一致。
- Java默认也不允许父到子转换,但如果确定父对象引用确实是子对象,可用强制类型转换。
- C#不提供基类强转成派生类的方法。
- Python提供了简单的转换方式type(<Derived Class>)(<Base Class>).
- JS ES6虽然引入了类,一般无必要做父类子类转换。
- Go/Rust并不是纯粹的OOP语言,需要做一些手脚。
枚举
- C/C++常规枚举可以和整形做隐式转换,C++11引入作用域为类的枚举,不允许此行为以加强安全性,但可以使用显式转换。
浮点数和整数的转换
- C/ObjC/C++/仓颉
浮点数转换成整数,会丢弃小数。
如何判断一个对象是否是某个类或者其子类?
纯编译型语言对此支持很差,ObjC以运行时查找方法而闻名,比C/C++的支持都优秀。
- ObjC提供isKindOfClass和isMemberOfClass方法可以轻松从运行时得到所属类的信息。
- C++提供dynamic_cast和typeid判断对象是否是某个类。
- Java/C#/Python/Swift/PHP/Ruby/JS等语言提供完善的类关系API,形如is*sub*class, is*kind*, *instance*of等等,因为它们的运行时足够强大,提供这些类关系信息易如反掌。
- PHP 提供 instanceof 方法。
若文章对您有帮助,欢迎关注 程序员小迷 。助您在编程路上越走越好!
微风不燥,阳光正好,你就像风一样经过这里,愿你停留的片刻温暖舒心。
我是 程序员小迷 (致力于C、C++、C#、Android、iOS、Java、Kotlin、Objective-C、Swift、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。