运行时类型识别

运行时的类型识别(RTTI)分为两类:
1.typeid操作符
2.dynamic_cast操作符
先看第二种:dynamic_cast完成将基类类型的指针或者引用安全转化为派生类类型的指针和引用。

对于指针,如果转化失败,则将指针置为NULL,对于引用类型,因为没有NULL,所以直接抛出bad_cast异常。下面是对应的例子:

#include <iostream>

using namespace std;


class Base1
{
public:
	virtual void func()
	{
		cout<<"base1 func!"<<endl;
	}
};

class Base2
{
public:
	virtual void func()
	{
		cout<<"base2 func!"<<endl;
	}
};

class Derived:public Base1
{
public:
	virtual void func()
	{
		cout<<"Derived func!"<<endl;
	}
};

int main()
{
	Base1* pb1 = new Derived;
	if(Derived* pd1 = dynamic_cast<Derived*>(pb1))
		pd1->func();
	else
		cout<<"转化失败"<<endl;

	Base2* pb2 = (Base2*)new Derived;
	if(Derived* pd2 = dynamic_cast<Derived*>(pb2))
		pd2->func();
	else
		cout<<"转化失败"<<endl;

	Derived d1;
	Base1& refb1 = d1;
	
	
	try{
		Derived& refd =  dynamic_cast<Derived&>(refb1);
		refd.func();
	}catch(bad_cast)
	{
		cout<<"转化失败"<<endl;
	}

	try
	{
		Base2& refb2 = dynamic_cast<Base2&>(d1);
		refb2.func();
	}
	catch(bad_cast)
	{
		cout<<"转化失败"<<endl;
	}
	
	return 0;
}
下面看typeid,它用来返回指针或者引用所指对象的实际类型。我们通常用它来测试两个指针或者两个引用的类型是否相等:

class E
{
public:
	void func()
	{
		cout<<"E"<<endl;
	}
};
class F:public E
{
	void func()
	{
		cout<<"F"<<endl;
	}
};
int main()
{
	
	Base1* pb = new Derived;
	Derived* pd = new Derived;
//	if(typeid(*pb) == typeid(*pb))
	if(typeid(*pb) == typeid(Derived))
		cout<<"相等"<<endl;
	else
		cout<<"不等"<<endl;
	E* pe = new F;
	F* pf = new F;
	if(typeid(*pe) == typeid(*pf))
		cout<<"相等"<<endl;
	else
		cout<<"不等"<<endl;

	return 0;
}

注意,对于没有虚函数的类,typeid返回的是指针的静态类型。注意,typeid中的参数是表示对象的表达式。
与typeid相关的一个概念,是type_info类。这个类的实现随编译器的变化而不同。但是它至少提供了4个函数:t1==t2 t1!=t2 t1.name() t1.before(t2)。创建type_info类唯一对象的方法是使用typeid操作符,其中的name函数很有意思,它将输出C风格的字符串,一般的情况下,输出与类型名有关:
  cout<<typeid(*pe).name()<<endl;

在vc++6.0和vs2010下,都会输出class E,而在有些编译器下输出的是1E,其中的1是名字饿长度。
vc++6.0需要:Project - settings... - C/C++ 在Category那里选 C++ Language 再在下边勾上 Enable Run-Time Type Information[RTTI]

至于什么时候用运行时类型识别,而不能用虚函数。书中给了一个很好的例子,假设类Derived继承自Base,并且添加了一些其他的数据成员,我们要为这个继承派生体系定义相等操作符,但是由于基类和派生类之间的转化关系,我们很难确定比较操作符的实际类型。所以,两个所以我们需要在比较操作时,先确定两个操作数的类型是否相同。如果不同,直接返回假,如果相同,那么在比较它们的数据是否相等。

#include <iostream>

using namespace std;
class Base
{
	friend bool operator==(const Base& lhs,const Base& rhs)
	{
		return (typeid(lhs) == typeid(rhs)) && (lhs.equal(rhs));
	}
public:
	Base(int i = 0):ival(i){}
	virtual bool equal(const Base& rhs)const
	{
		return ival == rhs.ival;
	}
protected:
	int ival;
};

class Derived:public Base
{
public:
	Derived(int i = 0,double d = 1.1):Base(i),dval(d){}
	bool equal(const Base& rhs)const
	{
		if(const Derived *dp = dynamic_cast<const Derived*>(&rhs))
		{
			return Base::equal(rhs) && dval == dp->dval;			
		}
		else
			return false;
	 }
private:
	double dval;
};
int main()
{
	
	Base b1;
	Base b2;
	Derived d1(1,1.1);
	Derived d2(2,2.2);
	if(d1 == d2)
		cout<<"yes"<<endl;
	else
		cout<<"no"<<endl;
	return 0;
}



PS:昨天去参加了一个笔试,竟然遇到了typeid的问题,(好变态啊好变态)所以狠下心,还是看看吧。

你可能感兴趣的:(c,测试,null,Class,编译器,2010)