C++_Primer_chapter18 2. 运行时类型识别

通过运行时类型识别(RTTI),程序能够使用基类的指针或引用来检索这些指针或引用所指向对象的实际派生类型

通过下面两个操作符提供RTTI( dynamic_cast 与typeid):

一、dynamic_cast

#include <iostream>
class base {
public:
	virtual ~base() {
	}
	virtual void isWhat() {
		std::cout << "base" << std::endl;
	}
};
class derived: public base {
public:
	void isWhat() {
		std::cout << "derived" << std::endl;
	}
};

int main() {
	
	base* bPtr = new derived();
	base& bRef = *bPtr;
	/*对于指针,如果转化失败,则将指针置为NULL*/
	if (derived* derPtr = dynamic_cast<derived*>(bPtr)) {
		derPtr->isWhat();
	}
	else {
		/* derPtr == NULL*/
	}

	/*对于引用类型,因为没有NULL,所以直接抛出bad_cast异常*/
	try {
		derived& derRef = dynamic_cast<derived&>(bRef);
		derRef.isWhat();
	}
	catch (std::bad_cast& e) {
		/* throw a bad_cast exception*/
	}
	return 0;
}

二、typeid

int main() {
	base* bPtr = new derived();
	base& bRef = *bPtr;
	if (typeid(*bPtr) == typeid(derived)) { // is "*bPtr" not "bPtr"
		bPtr->isWhat();
	}
	if (typeid(bRef) == typeid(*bPtr)) {
		bRef.isWhat();
	}
	return 0;
}
注意:对于没有虚函数的类,typeid返回的是指针的静态类型。


三、type_info

与typeid相关的一个概念,是type_info类。创建type_info类唯一对象的方法是使用typeid操作符。

至少提供了4个函数:t1==t2,  t1!=t2,  t1.name(),  t1.before(t2)。

int main() {
	base* bPtr = new derived();
	base& bRef = *bPtr;
	if (typeid(*bPtr) == typeid(derived)) { // is "*bPtr" not "bPtr"
		bPtr->isWhat();
	}
	if (typeid(bRef) == typeid(*bPtr)) {
		bRef.isWhat();
	}
	std::cout<<typeid(*bPtr).name()<<std::endl;

	base *ptr = new base();
	std::cout << typeid(*bPtr).before(typeid(*ptr)) << std::endl; // false
	std::cout << typeid(*ptr).before(typeid(*bPtr)) << std::endl; // true, 继承关系的先后顺序

	return 0;
}

四、RTTI的使用

假设类Derived继承自Base,并且添加了一些其他的数据成员,我们要为这个继承派生体系定义相等操作符,但是由于基类和派生类之间的转化关系,我们很难确定比较操作符的实际类型。所以,两个所以我们需要在比较操作时,先1)确定两个操作数的类型是否相同。如果不同,直接返回假,如果相同,那么2)再比较它们的数据是否相等。

class Base {
	friend bool operator==(const Base& lhs, const Base& rhs);
public:
	explicit Base(int b): base_elem(b) { // explicit 只能用于类内部的构造函数的申明上面
	}
	virtual ~Base() {
	}
private:
	int base_elem;
protected:
	virtual  bool equal(const Base& rhs) const { // 只比较base类成员,其他不管
		return rhs.base_elem == base_elem;
	}
};
class Derived : public Base {
	friend bool operator==(const Base& lhs, const Base& rhs);
public:
	Derived(int d, int b) : derived_elem(d), Base(b) {}
	virtual ~Derived() {
	}
	
private:
	int derived_elem;
protected: 
	virtual bool equal(const Base& rhs) const { 
		if (const Derived* ptr = dynamic_cast<const Derived*>(&rhs))
			return this->Base::equal(*ptr) && (derived_elem == ptr->derived_elem);
		else
			return false;
	}
};
// 简化了代码,无须再对 const Derived& 形参进行重载
bool operator == (const Base& lhs, const Base& rhs) {
	return (typeid(lhs) == typeid(rhs)) && (lhs.equal(rhs));
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值