什么是运行时类型信息?

2024年8月28日 | 阅读 4 分钟

运行时类型信息(RTTI),也称为运行时类型识别(RTI),是多种编程语言(如 C++、Object Pascal 和 Ada)的一个特性,它能在运行时提供一个对象的数据类型信息。运行时类型信息可以对所有类型可用,或者只对那些明确拥有此信息的类型可用(如 Ada 的情况)。一个更广泛的概念——类型内省,是运行时类型知识的一个特例。

运行时类型信息并非 C++ 原始设计的一部分,因为 Bjarne Stroustrup 认为这个特性经常被滥用。

简而言之,C++ 中的运行时类型信息(RTTI)是一种机制,它在运行时提供有关对象数据类型的信息,并且仅对包含至少一个虚函数的类可用。它允许程序在执行期间确定一个对象的类型。

什么是运行时转换?

使用指针或引用确定对象运行时类型的最简单方法是使用运行时转换,它会验证转换是否合法。如果我们需要将指针从一个基类转换到另一个基类,这非常有用。在处理决定其继承关系的类层次结构时,通常需要进行对象转换。转换分为两种:

  1. 向上转型 (Upcasting) - 当使用基类指针来处理派生类对象的指针或引用时。
  2. 向下转型 (Downcasting) - 当基类的引用或指针被更改为派生类的指针时。

使用 "dynamic_cast":在继承层次结构中,它用于将基类指针向下转型为子类指针。如果转换成功,它返回一个转换后类型的指针。如果我们尝试转换一个无效的类型,例如一个并非预期子类类型的对象指针,它就会失败。

概述

通过在 C++ 中使用 dynamic_cast<> 运算符,可以执行安全的类型转换,并且可以使用 typeid 运算符和 std::type_info 类来实时修改类型信息。在 Object Pascal 中,可以使用 as 运算符执行安全的类型转换。is 运算符可以用来确定对象所属的类,而 RTTI 单元中的类可以用来在运行时修改类型信息(例如:TRttiContext、TRttiInstanceType 等类)。在 Ada 中,带标签类型的对象也保留一个类型标签,用于运行时类型识别。如果一个对象是特定类型并且可以被正确地转换,可以使用 in 运算符在运行时进行测试。RTTI 只能用于多态类——即至少包含一个虚方法的类。实际上,这并不是一个限制,因为基类需要有虚析构函数,以便派生类的对象如果从基类指针被销毁时能执行正确的清理工作。

一些编译器有禁用 RTTI 的标志。在为内存有限的系统设计应用程序时,这些标志非常有用,因为它们可以减小应用程序的总体积。

什么是 C++ typeid?

可以使用 typeid 关键字在运行时确定对象的类。程序完成后,它返回一个指向 std::type_info 对象的指针。在只需要类信息而不需要多态的上下文中,typeid 通常比 dynamic_cast<class type> 更受欢迎,因为 typeid 始终是一个常数时间操作。相比之下,dynamic_cast 可能需要在运行时遍历其输入的类派生格。例如,std::type_info::name() 的行为是实现定义的,不能保证在不同编译器之间保持一致。

当对空指针使用一元 * 运算符来创建 typeid 表达式时,会抛出 std::bad_typeid 类的对象。对于其他无效的引用参数是否会引发异常,取决于具体的实现。换句话说,表达式必须是 typeid(*p) 的形式,其中 p 是任何产生空指针的表达式。

什么是 C++ dynamic_cast 和 Java cast?

在 C++ 中,可以使用 dynamic_cast 运算符将引用或指针向下转型为类层次结构中更精确的类型。与 static_cast 不同,dynamic_cast 的目标必须是指向类的指针或引用。它在运行时进行类型安全检查,而不是像 static_cast 和 C 风格类型转换那样在编译时进行类型检查。如果类型不兼容,当处理指针时会返回空指针,当处理引用时会抛出异常。

类似地,如果被转换的对象实际上不是目标类型的实例,并且不能通过语言定义的方法转换为目标类型,Java 的类型转换将抛出一个 java.lang.ClassCastException 实例。