RTTI
概念:
RTTI(Run Time Type Identification)即通过运行时类型识别,程序能够使用基类的指针或引用来检
查着这些指针或引用所指的对象的实际派生类型。
原因:
C++是一种静态类
型语言。其数据类型是在编译期就确定的,不能在运行时更改。然而由于面向对象程序设计中多态性的
要求,C++中的指针或引用(Reference)本身的类型,可能与它实际代表(指向或引用)的类型并不一致。
有时我们需要将一个多态指针转换为其实际指向对象的类型,就需要知道运行时的类型信息,这就产生
了运行时类型识别的要求。
在C++中为了支持 RTTI 提供了两个操作符:
- typeid 操作符,它在程序中可用于获取一个表达式的类型 ;
查询类型的信息, 类型。它指出指针或引用指向对象的实际派生类型。
- dynamic_cast 操作符可以用来把一个类类型对象的指针,转换成同一类层次结构中的其他类的指 针 ,同时也可以用它把一个类类型对象的左值,转换成同一类层次结构中其他类的引用。
dynamic_cast 和 typeid 操作符的操作数的类型 ,必须是带有一个或多个虚拟函数的类类型。 即对于 带有虚拟函数的类而言 RTTI 操作符是运行时刻的事件 ,而对于其他类而言,它只是编译时刻的事件。
1.typeid
C++顶层const和底层const
c++ primer里的原文:
指针本身是一个对象,它又可以指向另外一个对象。因此,指针本身是不是常量以及指针所指的是不是一个常量就是两个相互独立的问题。用名词顶层 const (top-level const)表示指针本身是个常量,而用名词底层 const(low-level const)表示指针所指的对象是一个常量。
更一般的,顶层 const 可以表示任意的对象是常量,这一点对任何数据类型都适用,如算术类型、类、指针等。底层 const 则与指针和引用等复合类型的基本类型部分有关。比较特殊的是,指针类型既可以是顶层 const 也可以是底层const,这一点和其他类型相比区别明显∶
举例:
int a = 0; const int *const p= a; //第二个const其实是const p,表示p这个指针本身是常量,即其中存放的地址不能变。 //第一个const,其实是 const *p, 表示*p不变,即其指向的对象不变。 //所以可以认为在第一个const是底层const,第二个const是顶层const. const int* p = nullptr; // 底层const int* const q = nullptr; // 顶层const
####所有情况下, typeid 都忽略顶层的 cv 限定符 。
int main()
{
const int a = 10;
int b = 20;
int*const pb = &b;
const int* const pa = &a;
cout<<"a : "<<typeid(a).name()<<endl;
cout<<"b : "<<typeid(b).name()<<endl;
cout<<"pa : "<<typeid(pa).name()<<endl;
cout<<"*pa : "<<typeid(*pa).name()<<endl;
cout<<"pb : "<<typeid(pb).name()<<endl;
cout<<"*pb : "<<typeid(*pb).name()<<endl;
return 0;
}
应用于多态类型的表达式时,typeid 表达式的求值可能涉及运行时开销(虚表查找),其他情况下
typeid 表达式都在编译时解决。
eg: 继承+多态:运行时开销
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x) {}
virtual ~Object() {}
};
class Base :public Object
{
private:
int num;
public:
Base(int x = 0) :num(x) {}
~Base() {}
};
int main()
{
Object obj;
Base base;
Object* op = &base;
Base* bp = &base;
cout << typeid(op).name() << " \t" << typeid(*op).name() << endl;
cout << typeid(bp).name() << " \t" << typeid(*bp).name() << endl;
}
运行结果:
图解:
对于含有虚函数的继承关系,对基类指针进行解引用或基类引用时:涉及运行时开销,需要查虚表
typeid(*op).name(); //查虚表
typeid(*bp).name(); //查虚表
void fun(Object& s); //查虚表
{
cout << typeid(s).name() << endl;
}fun(base); //查虚表
在C++中,提供了一个类,管理这个全局的数据结构,这个数据结构就是type_info;
typeid 操作符实际上返回一个类型为 type_info 的类对象。