05/01/2020
C++运行时类型识别
基础介绍1
运行时类型识别(runtime type identification, RTTI):
- typeid运算符,用于返回表达式的类型
- dynamic_cast 运算符,用于将基类指针或者基类引用安全地转换成派生类的指针或引用
应用
- 我们想使用基类对象的指针或者引用执行某个派生类操作并且该操作不是虚函数。相比较,使用虚函数比直接接管类型(即转换)好。
Base* b = new Derived;
Derived* d = dynamic_cast<Derived*>(b); //直接接管类型Derived类来管理或使用
dynamic_cast运算符
使用形式
- dynamic_cast<type*>(expression), 必须是一个有效的指针
- dynamic_cast<type&>(expression), 必须是一个左值
- dynamic_cast<type&&>(expression),不能是一个左值
- type必须是类类型,通常应该含有虚函数
- expression类型必须是type的公有派生类,或者是公有基类,或者相同的类型。必须是公有继承关系
- 运算符有返回值,失败返回0。如果是引用转换失败,会抛出bad_cast异常。
指针使用
//至少需要一个虚函数,不然无法通过编译,理由不知。
//虚函数表来确认动态绑定的类型,所以需要有虚函数。
class Base
{
public:
Base() = default;
int getX(){return x;}
virtual bool flag(){return false;} //虚函数展示了多态性
private:
int x = 1;
int y = 2;
};
class Derived:public Base
{
public:
Derived() = default;
Derived(std::string n,std::string a):name(n),actor(a)
{
}
std::string getName(){return name;}
std::string getActor(){return actor;}
private:
std::string name;
std::string actor;
};
class Derived2:public Base
{
public:
Derived2() = default;
Derived2(std::string n,std::string a):name(n),actor(a)
{
}
std::string getName(){return name;}
std::string getActor(){return actor;}
private:
std::string name;
std::string actor;
};
int main(){
Base* b = new Derived("jack","abc"); //静态类型Base,动态绑定了Derived
Derived* d = dynamic_cast<Derived*>(b);//转换成功
std::cout << d->getName()<<std::endl; //接管管理Derived
//如何安全的转换
if(Derived* d = dynamic_cast<Derived*>(b)) //失败返回0
return 0;
}
对于空指针执行dynamic_cast,返回所需类型的空指针
引用使用
//main
Derived d("jack","alex");
Base& b = d;
try
{
Derived& d2 = dynamic_cast<Derived&>(b);
std::cout << d2.getName()<<std::endl;
}catch(bad_cast)
{
}
dynamic_cast 和 static_cast 的区别
动态类型和静态类型转换的区别
- static_cast 运用在多个地方,例如继承转换,显式或隐式转换,但是dynamic_cast只运用于公有继承
- static_cast不安全,dynamic_cast有安全保护
typeid运算符
- 提问你的对象是什么类型
- typeid(expression),expression可以是任意类型,返回一个常量对象的引用,类型是type_info或者它的派生类
应用
- 顶层const会被忽略
- 如果是引用,返回该引用所引用的对象类型
- 数组或函数,不会返回指针类型
- 不是类类型,或者是类类型但是没有虚函数,返回静态类型
- 如果有虚函数,只能运行时候知道结果
例子1: 比较动态类型
Derived* d = new Derived();
Base* b = d;
if(typeid(*b)==typeid(*d))
{
std::cout << "They are same";
}
例子2:比较静态类型
if(typeid(b)==typeid(Derived)) //b是指针类型,比较静态类型
{
std::cout << "They are same";
}
std::cout << typeid(b).name();//可以输出,查看返回什么类型
type_info 类
- 头文件typeinfor
- 有一个name的成员函数,返回一个C风格字符串的对象类型的名字
- 重载了相等和不相等运算符
void add();
int arr[10];
std::cout << typeid(arr).name() << std::endl
<< typeid(std::string).name()<<std::endl
<< typeid(add).name()<<std::endl;
C++第五版 19.2.1 ↩︎