您的位置:首页 > 其它

RTTI(Run-Time Type Information,通过运行时类型信息) 运行期类型检查

2014-03-25 13:37 465 查看
RTTI提供了以下两个非常有用的操作符:

(1)typeid操作符,返回指针和引用所指的实际类型。

(2)dynamic_cast操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。


typeid函数

该函数的主要作用就是让用户知道当前的变量是什么类型的,比如使用typeid(a).name()就能知道变量a是什么类型的。因为typeid()函数是一个返回类型为const typeid_info&类型的函数,所以下面先对type_info类作下介绍


type_info类

该类的具体实现方式依编译器而定,但一般都有如下的成员定义

class type_info

{private:

type_info(const type_info &);

type_info& operator =(const type_info&); //type_info类的复制构造函数赋值运算符是私有的。

public:

virtual ~type_info(); //析构函数

bool operator = =(const type_info&) const; //在type_info类中重载了= =运算符,该运算符可以比较两个对象的类型是否相等。

bool operator !=(const type_info&)const; //重载的!=运算符,以比较两个对象的类型是否不相等

const char * name() const; //使用得较多的成员函数name,该函数反回对象的类型的名字。前面使用的typeid(a).name()就调用了该成员函数

bool before(const type_info&);};

因为type_info类的复制构造函数赋值运算符都是私有的,所以不允许用户自已创建type_info的对象,比如type_info
A;错误,没有默认的构造函数。唯一要使用type_info类的方法就是使用typeid函数。


typeid函数使用方式

、使用type_info类中的name()成员函数反回对象的类型的名称。其方法为:typeid(object).name()其中object是要显示其相应类型名的对象,该函数反回的名字因编译器而定。这里要注意的就是使用方式一中提到的虚函数类型的问题,即如果有类A,且有虚函数,类B,C,D都是从类A派生的,且都重定义了类A中的虚函数,这时有类A的指针p,再把对象类B的对象的地址赋给指针p,则typeid(p).name()将反回的类型将是A*,因为这里的p表示的是一个指针,该指针是类型为A的指针,所以反回A*,而typeid(*p).name()将反回B,因为指针p是指向类B的对象的,而*p就表示的是类B的对象,所以返回B。

2)、使用type_info类中重载的= =与!=比较两个对象的类型是否相等。使用该方法需要调用类type_info中重载的= =和!=操作符,其使用方法为typid(object1)= =typid(object2);如果两个对象的类型相等则反回1,如果不相等则为0。这种使用方法通常用于比较两个带有虚函数的类的对象是否相等,比如有类A,其中定义有虚函数,而类B,类C,类D,都是从类A派生而来的且重定义了该虚函数,这时有两个类A的指针p和p1,按照虚函数的原理,基类的指针可以指向任何派生类的对象,在这时就有可能需要比较两个指针是否指向同一个对象,这时就可以这样使用typeid了,typeid(*p)=
=typeid(*p1);这里要注意的是typeid(*p)与typeid(p)是指的不同的对象类型,typeid(p)表示的是p的类型,在这里p是一个指针,这个指针指向的是类A的对象,所以p的类型是A*,而typeid(*p)则不一样,*p表示的是指针p实际所指的对象的类型,比如这里的指针p指向派生类B,则typeid(*p)的类型为B。所以在测试两个指针的类型是否是相等时应使用*p,即typeid(*p)= =typeid(*p1)。如果是typeid(p)= =typeid(p1)的话,则无论指针p和p1指向的什么派生类对象,他们都是相等的,因为都是A
*的类型。


强制类型转换运算符

C++有四种强制类型转换符,分别是dynamic_castconst_caststatic_castreinterpret_cast。其中dynamic_cast与运行时类型转换密切相关,在这里我们介绍dynamic_cast。


dynamic_cast强制转换运算符

该转换符用于将一个指向派生类的基类指针或引用转换为派生类的指针或引用,注意dynamic_cast转换符只能用于含有虚函数的类,其表达式为dynamic_cast<类型>(表达式),其中的类型是指要将表达式转换成的目标类型,比如含有虚函数的基类B和从基类B派生出的派生类D,则B
*pb; D *pd, md; pb=&md; pd=dynamic<D*>(pb); 最后一条语句表示把指向派生类D的基类指针pb转换为派生类D的指针,然后将这个指针赋给派生类D的指针pd,有人可能会觉得这样做没有意义,既然指针pd要指向派生类为什么不pd=&md;这样做更直接呢?有些时候我们需要强制转换,比如如果指向派生类的基类指针B想访问派生类D中的除虚函数之外的成员时就需要把该指针转换为指向派生类D的指针,以达到访问派生类D中特有的成员的目的,比如派生类D中含有特有的成员函数g(),这时可以这样来访问该成员dynamic_cast<D*>(pb)->g();因为dynamic_cast转换后的结果是一个指向派生类的指针,所以可以这样访问派生类中特有的成员。但是该语句不影响原来的指针的类型,即基类指针pb仍然是指向基类B的。如果单独使用该指针仍然不能访问派生类中特有的成员。一般情况下不推见这样使用dynamic_cast转换符,因为dynamic_cast的转换并不会总是成功的,具体情况在后面介绍。


dynamic_cast的注意事项

dynamic_cast转换符只能用于指针或者引用。dynamic_cast转换符只能用于含有虚函数的类。dynamic_cast转换操作符在执行类型转换时首先将检查能否成功转换,如果能成功转换则转换之,如果转换失败,如果是指针则反回一个0值,如果是转换的是引用,则抛出一个bad_cast异常,所以在使用dynamic_cast转换之间应使用if语句对其转换成功与否进行测试,比如pd=dynamic_cast<D*>(pb);
if(pd){…}else{…},或者这样测试if(dynamic_cast<D*>(pb)){…}else{…}。


2typeid的注意事项编辑

使用 typeid 要注意一个问题,那就是某些编译器(如 Visual C++)默认状态是禁用 RTTI 的,目的是消除性能上的开销。如果你的程序确实使用了 RTTI,一定要记住在编译前启用 RTTI。(vc6.0启用方式:project->setting->c/c++->category->c++
Language 下面第二个复选框选中)。使用 typeid 可能产生一些将来的维护问题。
#include "stdafx.h"

#include "windows.h"

#include "DoubleSpreadsheetCell.h"

#include "StringSpreadsheetCell.h"

#include <typeinfo>

#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])

{

SpreadsheetCell* cellArray[3];

cellArray[0] = new StringSpreadsheetCell();

cellArray[1] = new StringSpreadsheetCell();

cellArray[2] = new DoubleSpreadsheetCell();

if(strcmp(("StringSpreadsheetCell"),typeid(*cellArray[0]).name()))

{

cout<<"StringSpreadsheetCell类1"<<endl;

}

if(typeid(*cellArray[0])==typeid(DoubleSpreadsheetCell))

{

cout<<"StringSpreadsheetCell类2"<<endl;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: