`
he91_com
  • 浏览: 374161 次
文章分类
社区版块
存档分类
最新评论

RTTI(dynamic_cast与typeid)

 
阅读更多
RTTI 运行时类型识别,程序能够使用基类的指针或引用来检索所指对象的实际派生类型
C++通过两个操作符提供RTTI
1.dynamic_cast 操作符,将基类的指针或引用安全的转换为派生类的指针或引用

2.typeid操作符,返回指针或引用所指对象的实际类型


dynamic_cast:
使用dynamic_cast模拟虚函数调用

请看下面这个小程序

#include <iostream>
using namespace std;

class A
{
public:
	void p() { cout<<"AAAAA"<<endl;}
	virtual void show() { cout<<"aaaaaaaaaa"<<endl;}
};

class B:public A
{
public:
	void p() { cout<<"BBBBB"<<endl;}
	void show() { cout<<"bbbbbbbbbb"<<endl;}
};

class C:public A
{
public:
	void p() { cout<<"CCCCC"<<endl;}
	void show() { cout<<"ccccccccccc"<<endl;}
};

class Factory
{
public:
	void show(A *a) 
	{ 
	if(B *b=dynamic_cast<B*>(a))
		b->p();
	else if(C *c=dynamic_cast<C*>(a))
		c->p();
	else
		cout<<"base class...";
	}
};

int main()
{
Factory *f=new Factory;
f->show(new C);
cout<<endl;
}

上面这个程序很简单,类B,C从类A继承,类A有个虚函数void show(),请注意void p()不是虚函数
f->show(new C) ->"CCCCC"
dynamic_cast=>实际上就是把基类的指针安全的转化为这个指针实际所指对象.
它执行两个操作,首先判断能否转化,也就是说看看你给我的是不是你想转换的对象,如果不能转化就失败。
这时,如果是转化到指针失败,返回0,如果转化到引用失败,则抛出bad_cast异常.如果可以转化则转换。


如上面,给f->show()的是指向C的指针,所以dynamic_cast<B*>(a),转换失败,返回0,执行dynamic_cast<C*>(a),
转换成功,输出“CCCCC”


这里有几点需要注意和思考:
1.class A必须至少有一个虚函数,即A必须是多态的.如果去掉A::void show()中的virtual,则报如下错误
cs.cc: 在成员函数‘void Factory::show(A*)’中:
cs.cc:38:28: 错误: 无法将‘a’从类型‘A*’动态转换到类型‘class B*’(源类型不是多态的)
cs.cc:40:33: 错误: 无法将‘a’从类型‘A*’动态转换到类型‘class C*’(源类型不是多态的)


2.有虚函数为什么还需要dynamic_cast?
在有些情况下是不可能使用虚函数的,如上,A::void p(),不是虚函数,这怎么办?
那改成虚函数不就好了吗?那如果改不了呢?比如使用第三方共享库,恰好就不是虚函数


3.那可不可以直接强制类型转换?
完全可以,但你会发现很多问题。
#1. A *a=new B; ((B*)a)->p(); //"BBBBB" (->优先级比类型转换高,所以需要加括号)
#2. A *a=new A; ((B*)a)->p(); //"BBBBB"
#3. A *a=new C; ((B*)a)->p(); //"BBBBB"
发现问题了没有,强制类型转换结果可能完全出乎意料,不是转换安全的。


4.RTTI解决虚函数解决不了的问题
如果我需要访问派生类独有的属性和方法,那么虚函数就无能为力了,这时候就是RTTI的天下了




typeid操作符:
typei表达式: typeid(c) ->>c是表示对象的任何表达式
返回结果是type_info的标准库类型的引用,type_info类提供==,!=操作,还有一成员函数name(),返回所表示的类型
名(不同系统产生结果不同)
如typeid(A)==typeid(B) ->false
typeid(A).name() ->"1A"


如重写上面 Factory::show() (使用typeid需要包含头文件typeinfo)

void show(A *a) 
	{ 
		if(typeid(*a)==typeid(B))
			((B*)a)->p();
		else if(typeid(*a)==typeid(C))
			((C*)a)->p();
		else
			cout<<"Bse class...";
	}

在这里我使用了强制类型转换,因为如果if为真,那么可以确定就是那个类型,所以还是转化安全的(个人意见)


这里需要注意几点:
#1.如果类A没有虚函数,那么void Factory::show()中typeid(*a),返回的将是操作数的静态类型,即typeid(*a)永远
等于typeid(A)


#2.如果main()中调用f->show(0);,那么如果A有一个虚函数,则typeid(*a)抛出一个bad_typeid异常,如果A没有一个虚函数,
则使用静态类型,则与#1同

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics