C++开发中级


864 浏览 5 years, 4 months

3.4 向上转型以及向下转型

版权声明: 转载请注明出处 http://www.codingsoho.com/

向上转型以及向下转型

您已经看到,对象可以转换为父类对象,或者赋值给父类。如果类型转换或者赋值是对某个普通对象执行,会产生截断:

Super mySuper = mySub; // SLICE

在这种情况下会导致截断,因为赋值结果是Super对象,而Super对象缺少Sub类中定义的附加功能。然而,如果用子类对父类的指针或者引用赋值,不会产生截断:

Super& mySuper = mySub; // No SLICE

这是通过超类使用子类的正确途径,也叫做向上转型(upcasting)。这也是让方法以及函数使用类的引用而不是直接使用类对象的原因。使用引用时,子类在传递时没有截断。

提示:当向上转型时,使用超类指针或者引用以避免截断。

因为无法保证对象实际上属于子类,专业的C++程序员通常不赞成将超类转换为一个子类,这种转换也叫做向下转型(downcasting)。例如,考虑下面的代码:

void presumptuous(Super inSuper)
{
    Sub * mySub = static_cast<Sub*>(inSuper);
    // Proceed to access Sub method on mySub
}

如果presumptuous()的作者还编写了调用presumptuous()的代码,那么可能一切正常,因为作者知道这个函数需要Sub*类型的参数。然而,如果其他程序员调用presumptuous(),他们可能传递一个Super*。编译时检测无法强制参数类型,因此函数盲目地假定inSuper实际上是一个指向Sub的指针。

向下转型有时是必须的,在可以控制的环境中您可以充分利用这种转换。然而,如果您打算进行向下转型,应该使用由dynamic_cast,从而使用对象内建的类型信息拒绝没有意义的类型转换。如果针对某个指针的dynamic_cast失败,这个指针的值将会是nullptr而不是指向某个无意义的数据。如果针对对象引用的dynamic_cast失败,将抛出std::bad_cast异常。

前面的示例应该这样编写:

void presumptuous(Super inSuper)
{
    Sub * mySub = dynamic_cast<Sub*>(inSuper);
    if(mySub != nullptr){
        // Proceed to access Sub method on mySub
    }
}

提示:仅在必要的情况下才使用向下转型,并且一定要到使用dynamic_cast。