C++ Primer第五版笔记——运行时类型识别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rest_in_peace/article/details/82968050

运行时类型识别(run-time type identification,RTTI)的功能由两个运算符实现:
 typeid运算符,用于返回表达式的类型。
 dynamic_cast运算符,用于将基类的指针或引用安全的转换成派生类的指针或引用。
 当这两个运算符用于某种类型的指针或引用,并且该类型含有虚函数时,运算符将使用指针或引用所绑定的对象的动态类型。
 这两个运算符适用于以下情况:使用基类对象的指针或引用执行某个派生类的操作并且该操作不是虚函数(在可能的情况下还是优先使用定义虚函数的方式)。


dynamic_cast运算符

使用形式:

dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)

其中type必须是一个类类型,并且通常情况下该类型应该有虚函数。第一个形式中,e必须是一个有效的指针;第二个形式中,e必须是一个左值;第三个形式中,e不能一个左值。
在上面的所有形式中,e的类型必须符合以下三个条件中的任何一个:
1、e的类型与type的类型相同;
2、e的类型与type的公有派生类的类型相同;
3、e的类型与type的公有基类的类型相同。
符合条件的情况下,类型转换可以成功;否则会失败。如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0;如果转换目标是引用类型并且失败了,则会抛出bad_cast异常。

指针类型的dynamic_cast
  假定Base类至少含有一个虚函数,Derived是Base的公有派生类。如果有一个Base的指针bp,则我们可以在运行时将它转换成指向Derived的指针:

if(Derived* dp = dynamic_cast<Derived*>(bp)){
	//。。。
}else{
	//。。。
}

如果bp指向Derived对象,则上述类型转换初始化dp并令其指向bp指向的Derived对象。类型转换失败的情况下,其结果为0,dp为0意味着if条件失败。
(此处的dp是局部变量,这样做的好处是可以在一条语句中完成类型转换和条件检查两项任务,且dp在if外部不会被访问到)。

引用类型的dynamic_cast
  引用类型的dynamic_cast与指针类型的dynamic_cast在表示错误发生的方式上略有不同。因为不存在空引用,因此当对引用类型转换失败时,程序抛出一个名为std::bad_cast的异常,该异常定义在typeinfo标准库头文件中。

void f(const Base& b){
	try{
		const Derived& d = dynamic_cast<const Derived&>(b);
		//。。。
	}catch(bad_cast){
	//。。。
	}
}

typeid运算符

该运算符允许程序向表达式提问:你的对象时什么类型?其表达式形式如:typeid(e)。其中e可以是任意表达式或者类型的名字。其结果是一个常量对象的引用,该对象的类型是标准库类型type_info或type_info的公有派生类型(该类定义在typeinfo头文件)。

使用typeid运算符
  通常情况下,使用该运算符来比较两个表达式的类型是否相同,或者比较一条表达式与指定类型是否相同:

Derived* dp = new Derived;
Base* bp = dp;						//两个指针都指向Derived对象
//在运行时比较两个对象的类型
if(typeid(*dp) == typeid(*bp)){
	//。。。
}
//检查运行时类型是否和指定类型相同
if(typeid(*bp) == typeid(Derived)){
	//。。。
}

第一个if语句,比较bp和dp所指向的对象的动态类型是否相同,第二个if判断bp指向的对象是否是Derived对象。

typeid是否需要运行时检查决定了表达式是否会被求值,只有当类型含有虚函数时,编译器才会对表达式求值。反之,如果类型不含有虚函数,则typeid返回表达式的静态类型(编译器无需对表达式求值也能知道表达式的静态类型)。


例子

class Base{
	friend bool operator==(const Base&,const Base&);
public:
	//Base接口成员
protected:
	virtual bool equal(const Base&) const;
	//Base的数据成员和其他用于实现的成员
};	
class Derived:public Base{
public:
	//Derived的接口成员
protected:
	bool equal(const Base&) const;
	//Derived的数据成员和其他用于实现的成员
};

bool operator==(const Base& lhs,const Base& rhs){
	//如果typeid不相同,返回false,否则虚调用equal
	return typeid(lhs) == typeid(rhs) && lhs.equal(rhs);
}

bool Derived::equal(const Base& rhs) const{
	auto r = dynamic_cast<const Deived&>(rhs);
	//。。。
}
bool Base::equal(const Base& rhs) const{
	//。。。
}


猜你喜欢

转载自blog.csdn.net/rest_in_peace/article/details/82968050