类型身份证 · RTTI
在 C++ 的世界里,每个类型都有自己的"身份证"。当你拿到一个基类指针时,如何知道它实际指向的是什么类型的对象?这就是 RTTI(Run-Time Type Information,运行时类型信息)的用武之地。
typeid 运算符
typeid 是查询类型信息的基本工具:
#include <iostream>
#include <typeinfo>
class Animal
{
public:
virtual ~Animal() = default;
virtual void speak() = 0;
};
class Dog : public Animal
{
public:
void speak() override { std::cout << "Woof!" << std::endl; }
};
class Cat : public Animal
{
public:
void speak() override { std::cout << "Meow!" << std::endl; }
};
int main()
{
// 基本类型
int x = 42;
std::cout << "Type of x: " << typeid(x).name() << std::endl;
std::cout << "Type of 3.14: " << typeid(3.14).name() << std::endl;
// 类类型
Dog dog;
Cat cat;
std::cout << "Type of dog: " << typeid(dog).name() << std::endl;
std::cout << "Type of cat: " << typeid(cat).name() << std::endl;
// 多态类型(通过基类指针)
Animal* animal = &dog;
std::cout << "Type of *animal: " << typeid(*animal).name() << std::endl;
animal = &cat;
std::cout << "Type of *animal: " << typeid(*animal).name() << std::endl;
return 0;
}注意:
typeid().name()的输出是编译器相关的,可能是修饰过的名称。
type_info 类
typeid 返回 std::type_info 对象的引用:
dynamic_cast:安全的向下转型
dynamic_cast 用于在继承层次中安全地转换指针或引用:
引用的 dynamic_cast
对引用使用 dynamic_cast 时,失败会抛出异常:
RTTI 的性能考量
RTTI 有一定的运行时开销。在性能敏感的代码中,有几种替代方案:
1. 虚函数代替 dynamic_cast
2. 枚举类型标记
访问者模式:类型安全的替代方案
std::any 与 std::variant(C++17)
现代 C++ 提供了类型安全的动态类型容器:
实现简单的反射系统
禁用 RTTI
在某些嵌入式系统或对代码大小敏感的环境中,可以禁用 RTTI:
总结
特性
用途
性能
typeid
获取类型信息
中等
dynamic_cast
安全向下转型
较慢
虚函数
多态行为
快
枚举标记
类型识别
最快
访问者模式
类型安全的双分派
快
std::any
类型擦除容器
中等
std::variant
类型安全的联合
快
RTTI 是 C++ 的强大特性,但要明智地使用。在性能关键的代码中,考虑使用虚函数或其他替代方案。记住:每个类型都有自己的"身份证",但查验身份证是要付出代价的!
Last updated