向上转型和向下转型
派生类对象可以转换为父类的对象,或者赋值给父类,示例(Derived继承Base类):
Base myBase {myDerivd};
这种情况下会导致截断,因为赋值结果是Base
类的对象,而Base
类的对象缺少Dervied
类中定义的附加功能。然而,如果用派生类对基类的指针或引用赋值,则不会产生截断:
Base& myBase {myDerived}
这是通过基类使用派生类的正确途径,也被称为向上转型。这也是让方法和函数使用类的引用而不是直接使用类的对象的原因。通过使用引用,派生类在传递的时候没有发生截断。
将基类转换为派生类也被称为向下转型,专业的c++程序员一般是不会使用这种转换的。因为无法保证对象实际上属于派生类,也因为向下转型是不好的设计。
例如:
void func(Base *base)
{
Derived* myDerived {static_cast<Derived*>(base)};
}
如果func
函数及其所有调用func
函数的函数都是一个人所写,那么没啥太大问题,毕竟作者自己知道这个函数需要Derived*
类型的参数。但是如果说其他程序员调用该函数,他们可能传递Base*
,编译期的检测无法强制参数类型。因此函数盲目的假定参数base
实际上是一个指向Derived
对象的指针。
向下转型有时候又是必须的,在可控的环境下可以充分利用这种转换。如果打算使用这种转换,应该使用dynamic_cast()
,以使用对象的内建类型信息,拒绝没有意义的类型转换,这种内建信息通常驻留在虚表中,这意味着dynamic_cast()
只能用于具有虚表的对象,即至少有一个虚成员的对象。如果针对某个指针的dynamic_cast()
失败,这个指针的值就是nullptr
,而不是指向某个无意义的数据。