为什么从类到子类的动态转换要求类是多态的?

时间:2010-02-09 13:34:21

标签: c++ casting rtti

据我了解,动态强制转换与静态强制转换的不同之处在于它对RTTI的使用,以及如果变量的动态类型 - 从基础转换为派生 - 不适合时,它会失败的事实。但是,如果我们还有RTTI,为什么这个类必须是多态的呢?

编辑:由于对“多态”一词的使用存在一些混淆,这里是cplusplus.com中的条目,促使我这样说:

  

dynamic_cast只能用于指针和对象的引用。其目的是确保类型转换的结果是所请求类的有效完整对象。

     

因此,当我们将一个类转换为其基础

时,dynamic_cast总是成功的
classes: class CBase { };
class CDerived: public CBase { };

CBase b; CBase* pb; CDerived d;
CDerived* pd;

pb = dynamic_cast<CBase*>(&d);     //ok: derived-to-base 
pd = dynamic_cast<CDerived*>(&b);  //wrong: base-to-derived 
  

这段代码中的第二次转换会产生编译错误,因为除非基类是多态的,否则不允许使用dynamic_cast进行基本到派生的转换。

http://www.cplusplus.com/doc/tutorial/typecasting/

4 个答案:

答案 0 :(得分:7)

RTTI信息仅适用于拥有虚拟会员的班级。 (假定的实现是vtable包含dynamic_cast工作所需的内容;你可以计算出其他方案,但是在对象中都需要一个类型标识符,为什么不使用vptr?)

答案 1 :(得分:1)

如果没有继承关系,您可以使用哪种指针?可以在指向不同类型的对象的指针之间执行的唯一合法和合理的强制转换(忽略const强制转换)在同一继承层次结构中。

编辑:在dynamic_cast第14.2.2.2节的D&amp; E书中引用BS:

  

此外,一个虚拟的类   函数通常称为a   多态类和多态   类是唯一可以的类   通过基类安全操作   ......从编程的角度来看,   因此,提供它似乎很自然   RTTI仅适用于多态类型。

我的重点。

答案 2 :(得分:1)

涉及运行时类型识别。 dynamic_cast必须在运行时检查向下转换的有效性(如果转换为不合适的类型,则返回NULL指针/抛出异常)。

该标准规定,对于多态类型,typeid指的是对象的 dynamic 类型(大多数派生的),对于其他类型,它指的是 static 类型的对象

如果相关类型未提供任何动态类型信息,我认为动态 _cast无法确定转码的有效性。对于非多态Base,只有Base*,它没有动态的大多数派生类型,可以在运行时检查。

另一方面,上传的有效性可以在编译时静态确定。

答案 3 :(得分:0)

class Base
{
public:
    virtual ~Base()
    {
        std::cout << "Base" << std::endl;
    }
};

class Derived : public Base
{
public:
    ~Derived() 
    {
        std::cout << "Derived" << std::endl;
    }
};

int main()
{

    Base b; Base* pb; Derived d; 
    Derived* pd;
    Derived* thisWillBeNull = 0;
    Base *pBase = new Derived();

    pb = dynamic_cast<Base*>(&d);     //ok: derived-to-base  
    thisWillBeNull = dynamic_cast<Derived*>(&b);  //null 

    pd = dynamic_cast<Derived*>(pDerived);  

delete pDerived;

return 0;

}

Base类必须至少具有虚拟析构函数。不声明虚拟析构函数 可能会引入内存泄漏,因为不会调用派生析构函数。

thisWillBeNull = dynamic_cast<Derived*>(&b);  

如果RTTI打开,这行代码将导致空指针。如果未启用RTTI,则该行会导致运行时错误。