STL之RTTI

来源:互联网 发布:哪个软件购票方便 编辑:程序博客网 时间:2024/05/29 11:51

RTTI(Run-Time Type Information)的相关内容包括typeid、dynamic_cast这两个关键字,和头文件<typeinfo>。

typeid的作用是在程序运行时,返回对象的类型,用起来极像一个普通函数,返回值是const type_info。同sizeof类似,typeid可接受一个类型或变量。

type_info在<typeinfo>中定义,必须在typeid运算符的使用之前包含此头文件。

除了type_info,<typeinfo>中还定义了两个异常:

  // 如果dynamic_cast执行失败, 会抛出bad_cast异常  class bad_cast : public exception  {  public:    bad_cast() throw() { }    virtual ~bad_cast() throw();    virtual const char* what() const throw();  };  // 如果交给typeid的参数是空指针, 抛出此异常  class bad_typeid : public exception  {  public:    bad_typeid () throw() { }    virtual ~bad_typeid() throw();    virtual const char* what() const throw();  };

type_info的public成员有:

virtual ~type_info();/** 返回一个实现定义的字符串, 不可移植, 同种类型的type_info对象的name()返回的字符串相同, 不同类型对应的字符串则不同 */const char* name() const;/** 是否before参数标识的类型, 不同编译器实现可能不同, 不同程序之间返回值可能也不同, 同一程序不同时间运行结果可能也不一样, 你是来搞笑的吗? */bool before(const type_info& arg) const;bool operator==(const type_info& arg) const;bool operator!=(const type_info& arg) const

是的,它的默认构造函数,拷贝构造函数,赋值运算符都是private或protected的。这样,你就不能建立一个type_info类型的对象,只能通过typeid运算符来获得type_info对象。

typeid主要用来在多态中判断一个基类指针或引用是否指向派生类对象。


下面开始介绍4个强制类型转换操作符
c++里有4个强制类型转换操作符,分别是 static_cast, dynamic_cast,const_cast,reinterpret_cast。
它们用起来像模板函数。

一、reinterpret_cast
reinterpret_cast<type-id> (expression)
reinterpret是重新解释的意思,reinterpret_cast仅用来对内存地址进行变换操作。做的是c里直接操纵内存的事,我觉得还不如用c风格的强制转换。
type-id必须是一个指针、引用、常量表达式、或成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。
不要用reinterpret_cast。(以上内容,有我自己的猜测,不可妄信)

二、const_cast
const_cast<type-id> (expression)
该运算符用来修改类型的const或volatile属性。
type-id必须是指针,引用,或指向数据成员的指针。
尽量不要用,用了说明程序设计不良。

三、static_cast
没有运行时类型检查来保证转换的安全性,用法有:
① 用于类层次结构中基类和派生类之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的指针。
④把任何类型的表达式转换成void类型。

四、dynamic_cast
dynamic_cast是RTTI的一部分,在运行时进行类型转换,前三个则是在编译时进行转换。
该转换符用于将一个指向派生类的基类指针或引用转换为派生类的指针或引用。
注意dynamic_cast转换符只能用于含有虚函数的类,只能用于指针或引用。
如果转换失败,如果是指针则反回一个0值,如果是转换的是引用,则抛出一个bad_cast异常。

有些时候我们需要强制转换,比如如果指向派生类的基类指针B想访问派生类D中的除虚函数之外的成员时就需要把该指针转换为指向派生类D的指针,以达到访问派生类D中特有的成员的目的,比如派生类D中含有特有的成员函数g(),这时可以这样来访问该成员

dynamic_cast<D*>(pb)->g();

因为dynamic_cast转换后的结果是一个指向派生类的指针,所以可以这样访问派生类中特有的成员。但是该语句不影响原来的指针的类型,即基类指针pb仍然是指向基类B的。

另外,dynamic_cast还支持交叉转换(cross cast),如下代码所示:

class A {public:    int m_iNum;    virtual void f(){}};class B:public A {};class D:public A {};void foo() {    B *pb = new B;    pb->m_iNum = 100;    D *pd1 = static_cast<D*>(pb); // compile error    D *pd2 = dynamic_cast<D*>(pb); // pd2 is NULL    delete pb;}

不过,这有什么鸟用?总会转换失败,而且这转换也没有意义。大概dynamic_cast是通过虚函数表实现的,这是一个副作用吧!?


reinterpret_cast和static_cast的不同:

class A{public:    int m_a;};class B{public:    int m_b;};class C : public A, public B {};int main(){    C c;    printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast<B*>(&c));    return 0;}

输出:
0028FF18, 0028FF18, 0028FF1C

reinterpret_cast就是对地址强制转换而已,static_cast则是安全的转换。

0 0
原创粉丝点击