C++ 运行时类型识别(RTTI)
C++以虚函数的形式支持了多态,某种形式上支持了运行时类型决议;但是
dynamic_cast
可以做到更多,在运行时对类型做出判断然后决定是否进行转换;其本质在于在虚函数表中存储了类的信息
typeid关键字和type_info类
typeid
是C++中的关键字,类似于sizeof
可以获取类、类实例的type_info
对象的引用;需要注意的是如果表达式含有虚函数表,那么会在运行时获取表达式动态类型,否则在编译时获取表达式的静态类型
type_info接口
operator=[deleted] //禁止拷贝
bool operator==( const type_info& rhs ) const; //判断是否相等
bool operator!=( const type_info& rhs ) const; //判断是否不等
bool before( const type_info& rhs ) const; //rhs类是否在出现在本类前
const char* name() const; //返回类型名
#include <stdio.h>
#include <stdlib.h>
#include <typeinfo>
class Parent
{
public:
virtual void tt(){};
};
class Son: public Parent
{
};
class Test_A {
};
class Test_B : public Test_A{
};
int main()
{
Parent *p1 = new Son();
Son *s1 = new Son();
Test_A *ta = new Test_A();
printf("ptr type Son: %s, Parent: %s, Test_A: %s\n", typeid(s1).name(), typeid(p1).name(), typeid(ta).name());
printf("obj Son: %s, Parent: %s, Test_A: %s\n", typeid(*s1).name(), typeid(*p1).name(), typeid(*ta).name());
printf("type Son: %s, Parent: %s, Test_A: %s\n", typeid(Son).name(), typeid(Parent).name(), typeid(Test_A).name());
printf("successtion: %d, %d\n", typeid(Son).before(typeid(Parent)), typeid(Parent).before(typeid(Son)));
Test_A *tb = new Test_B();
printf("type tb: %s,\n", typeid(tb).name());
}
ptr type Son: P3Son, Parent: P6Parent, Test_A: P6Test_A
obj Son: 3Son, Parent: 3Son, Test_A: 6Test_A
type Son: 3Son, Parent: 6Parent, Test_A: 6Test_A
successtion: 1, 0
type tb: 6Test_A
-
type_info
的name
并不是类名,但是和类名有关可以看出来 - 类实例和类指针的类型是不一样的
- 只有拥有虚函数,类实例才能在运行时获取真正的类型
dynamic_cast
类型转换
dynamic_cast
支持指针和引用的转换,只有存在相关性时才能够转换成功;对于指针类型,转换失败返回nullptr
,对于引用类型,转换失败抛出bad_cast
异常;同样时依赖于虚函数表进行的动态类型识别
class Parent
{
public:
virtual void tt(){};
};
class Son: public Parent
{
};
class Test_A {
};
class Test_B : public Test_A{
};
int main()
{
Parent *p1 = new Parent();
Son *s1 = dynamic_cast<Son*>(p1); //succ
Test_A *ta = new Test_A();
//Test_B *tb = dynamic_cast<Test_B*>(ta); //fail
return 0;
}
在虚函数表中会存储类的type_info
数据,但是具体实现由编译器来进行处理;这里就不继续分析了
网友评论