RTTI C++ 运行时类型识别

来源:互联网 发布:精易模块源码 编辑:程序博客网 时间:2024/06/02 05:02

RTTI C++ 运行时类型识别

 

 

通过RTTI,能够通过基类的指针或引用来检索其所指对象的实际类型。c++通过下面两个操作符提供RTTI。

(1)typeid:返回指针或引用所指对象的实际类型。

(2)dynamic_cast:将基类类型的指针或引用安全的转换为派生类型的指针或引用。

对于带虚函数的类,在运行时执行RTTI操作符,返回动态类型信息;对于其他类型,在编译时执行RTTI,返回静态类型信息。

当具有基类的指针或引用,但需要执行派生类操作时,需要动态的强制类型转换(dynamic_cast)。这种机制的使用容易出错,最好以虚函数机制代替之。

dynamic_cast 操作符

如果dynamic_cast转换指针类型失败,则返回0;如果转换引用类型失败,则抛出一个bad_cast类型的异常。

可以对值为0的指针使用dynamic_cast,结果为0。

dynamic_cast会首先验证转换是否有效,只有转换有效,操作符才进行实际的转换。

if (Derived *derivedPtr = dynamic_cast<Derived *>(basePtr)){    // use the Derived object to which derivedPtr points}else{ // basePtr points at a Base object    // use the Base object to which basePtr points}

也可以使用dynamic_cast将基类引用转换为派生类引用:dynamic_cast<Type&>(val)

因为不存在空引用,所以不能像指针一样对转换结果进行判断。不过转换引用类型失败时,会抛出std::bad_cast异常。

try{     const Derived &d = dynamic_cast<const Derived&>(b);}catch (bad_cast) {    // handle the fact that the cast failed.}

typeid操作符

typeid能够获取一个表达式的类型:typeid(e)。

如果操作数不是类类型或者是没有虚函数的类,则获取其静态类型;如果操作数是定义了虚函数的类类型,则计算运行时类型。

typeid最常见的用途是比较两个表达式的类型,或者将表达式的类型与特定类型相比较。

Base *bp;Derived *dp;// compare type at run time of two objectsif (typeid(*bp) == typeid(*dp)){    // bp and dp point to objects of the same type}// test whether run time type is a specific typeif (typeid(*bp) == typeid(Derived)){    // bp actually points a Derived}

注意:如果是typeid(bp),则是对指针进行测试,这会返回指针(bp)的静态编译时类型(Base *)。

如果指针p的值是0,,并且指针所指的类型是带虚函数的类型,则typeid(*p)抛出一个bad_typeid异常。

 

Dynamic_cast 相当有用,当我们的基类不能修改时,可以用Dynamic_cast进行转换,比如以前我做过一个客户端的程序,在不同的对话框中都要显示图像,为了方便,我定义了一个基类,其它的需要显示图像的对话框都继承该基类,为了减少重复代码,我在ShowImage的函数放在基类里面,调用的参数里面有一个Picture Control Id,

   if (this==NULL)
   {
    return ;
   }

   CWnd *pCurrent = dynamic_cast<CWnd*>(this);

   if (pCurrent==NULL)
   {
    return ;
   }

   pWnd= pCurrent->GetDlgItem(PictureControlID);

 

这样就得到了子对话框的picture控件句柄;然后在该picture控件上画图;

 

另外的例子,转自网上:

典型案例:
Wicrosoft公司提供给我们一个类库,其中提供一个类Employee.以头文件Eemployee.h和类库.lib分发给用户
显然我们并无法得到类的实现的源代码

//Emplyee.h
class Employee 
{
public:
    
virtual int salary();
};

class Manager : public Employee
{
public
    
int salary();
};

class Programmer : public Employee
{
public:
    
int salary();
};


我们公司在开发的时候建立有如下类:

class MyCompany
{
public:
    
void payroll(Employee *pe);
    
//
};

void MyCompany::payroll(Employee *pe)
{
    
//do something
}


但是开发到后期,我们希望能增加一个bonus()的成员函数到W$公司提供的类层次中。
假设我们知道源代码的情况下,很简单,增加虚函数:

//Emplyee.h
class Employee 
{
public:
    
virtual int salary();
    
virtual int bonus();
};

class Manager : public Employee
{
public
    
int salary();
};

class Programmer : public Employee
{
public:
    
int salary();
    
int bonus();
};

//Emplyee.cpp

int Programmer::bonus()
{
    
//
}

payroll()通过多态来调用bonus()

class MyCompany
{
public:
    
void payroll(Employee *pe);
    
//
};

void MyCompany::payroll(Employee *pe)
{
    
//do something
    //pe->bonus();
}


但是现在情况是,我们并不能修改源代码,怎么办?dynamic_cast华丽登场了!
在Employee.h中增加bonus()声明,在另一个地方定义此函数,修改调用函数payroll().重新编译,ok

//Emplyee.h
class Employee 
{
public:
    
virtual int salary();
};

class Manager : public Employee
{
public
    
int salary();
};

class Programmer : public Employee
{
public:
    
int salary();
    
int bonus();//直接在这里扩展
};

//somewhere.cpp

int Programmer::bonus()
{
    
//define
}


 

class MyCompany
{
public:
    
void payroll(Employee *pe);
    
//
};

void MyCompany::payroll(Employee *pe)
{
    Programmer 
*pm = dynamic_cast<Programmer *>(pe);
    
    
//如果pe实际指向一个Programmer对象,dynamic_cast成功,并且开始指向Programmer对象起始处
    if(pm)
    {
        
//call Programmer::bonus()
    }
    //如果pe不是实际指向Programmer对象,dynamic_cast失败,并且pm = 0
    
else
    {
        
//use Employee member functions
    }
}




dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。

在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

 

附;

1)const_cast

说明:该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。

 

2)reinpreter_cast

说明:type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。

 

3)static_cast

说明:该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。
为什么需要static_cast强制转换?
情况1:void指针->其他类型指针;
情况2:改变通常的标准转换;
情况3:避免出现可能多种转换的歧义;

 

它主要有如下几种用法:

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

注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。

 

http://www.cnblogs.com/jerry19880126/archive/2012/08/14/2638192.html

0 0
原创粉丝点击