第22章:run time type information

运行时类型识别的功能由两个运算符实现:

1:typeid 运算符:用于返回表达式的类型;
2:dynamic_cast 运算符:用于将基类的指针或引用安全的转化为派生类的指针或引用。

当我们将这两个运算符用于某种类型的指针或引用时,并且该类型含有虚函数时,运算符将使用指针或引用所绑定对象的动态类型。

一:dynamic_cast运算符:

dynamic_cast运算符的使用形式如下所示:

dynamic_cast<type*>(e);
dynamic_cast<type&>(e);
dynamic_cast<type&&>(e);

其中, type必须要是一个类类型,并且该类型必须要含有虚函数。在第一种形式下,e必须要是一个有效的指针;在第二种形式下,e必须是一个左值,在第三种形式下,e不能是左值;

在上述所有形式中,e的类型必须符合以下三个条件中任意一个:e的类型是目标type的公有派生类,e的类型是目标type的公有基类或者e的类型就是目标type的类型。如果符合,则类型转换成功,否则,转换失败。如果一条dynamic_cast的转换目标类型是指针并且转换失败了,则结果是0;如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个bad_cast异常。

1:指针类型的dynamic_cast

举个简单例子,假设Base类至少含有一个虚函数,Derived是Base的公有派生类。如果有一个指向Base的指针bp,则我们可以在运行时将其转换为指向Derived指针。具体代码如下:

if( Derived* dp=dynamic_cast<Derived*>(bp))
{ //使用dp指向的Derived对象;
}
else { //使用bp指向的Base对象;
}

如果bp指向Derived对象,则上述类型转换初始化dp并令其指向bp所指向的Derived对象,此时if内部使用Derived内部的代码是安全的。如果bp指向的实际类型是Base类型,则转换的结果为0,dp为0意味着if条件语句失败,此时else字句执行相应的Base操作。

2:引用类型的dynamic_cast

引用类型的dynamic_cast与指针类型的dynamic_cast表达错误的发生的方式上略有不同。因为不存在所谓的空引用,所以对于引用类型来说,无法使用与指针类型完全相同的错误报告策略。当对引用的类型转换失败时,程序抛出一个std::bad_cast的异常,该异常定义在typeinfo标准库头文件中。

我们可以按照如下的形式改写之前的程序,令其使用引用类型。代码如下:

void f(const Base& b)
{
    try{
        const Derived& d=dynamic_cast<const Derived&>(b);
        //使用b引用的Derived对象;
    }
    catch(bad_cast){
        //处理类型转换失败的情况;
    }
}       

二:typeid运算符

typeid表达式的形式是typeid(e),其中e可以是任意表达式或类型的名字。typeid操作的结果是一个常量对象的引用,该对象的类型是标准库类型type_info或者是其公有派生类。

typeid运算符可以作用于任意类型的表达式。和往常一样,顶层const被忽略,如果表达式是一个引用,则typeid返回该引用所引对象的类型。不过当typeid作用于数组或函数时,并不会执行向指针的标准类型转换,也就是说,当我们对数组a执行typeid(a),则所得的结果是数组类型而非指针类型。

当运算对象不属于类类型或者是一个不包含任何虚函数的类时,typeid运算符指示的是运算对象的静态类型,并且当typeid作用于指针时(而非指针所指向的对象),返回的结果也是该指针的静态编译类型。而当运算对象是定义了至少一个虚函数类的左值时,typeid的结果直到运行时才会求得。

通常情况下,我们使用typeid比较两条表达式的类型是否相同,或者比较一条表达式的类型是否与指定类型相同。

Derived* dp=new Derived;
Base* bp=dp;            //两个指针都指向Derived对象;

//在运行时比较两个对象的类型;
if(typeid(*dp)=typeid(*bp)){
//bp和dp指向同一类型的对象;
}

//检查运行时类型是否是某种指定的类型
if(typeid(*bp)=typeid(Derived)){
//bp实际指向Derived对象;
}

typeid是否需要运行时检查决定了表达式是否会被求值。只有当类型含有虚函数时,编译器才会对表达式求值。反之,如果类型不含有虚函数,则typeid返回表达式的静态类型;编译器无需对表达式求值也能知道表达式的静态类型。

如果表达式的动态类型可能与静态类型不同,则必须在运行时对表达式求值以确定返回的类型。这条规则适用于typeid(*p)的情况。如果指针p所指向的类型不含有虚函数,则p不必非得是一个有效的指针。否则,*p将在运行时求值,此时p必须是一个有效的指针。如果p是一个空指针,则typeid(*p)将抛出一个名为bad_typeid的异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值