您的位置:首页 > 编程语言 > C语言/C++

RTTI C++ 运行时类型识别

2014-04-14 14:43 337 查看
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 objects
if (typeid(*bp) == typeid(*dp))
{
// bp and dp point to objects of the same type
}
// test whether run time type is a specific type
if (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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: