2

据我了解,动态转换与静态转换的不同之处在于它对 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

4 回答 4

7

RTTI 信息仅适用于具有虚拟成员的类。(假设的实现是 vtable 包含 dynamic_cast 工作所需的内容;您可以制定其他方案,但都需要对象中的类型标识符,那么为什么不使用 vptr 呢?)

于 2010-02-09T13:38:52.010 回答
2

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

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

如果所讨论的类型不提供任何动态类型信息,我想动态_cast 无法确定向下转换的有效性。对于非多态基础,a就是这样,它没有可以在运行时检查的动态最派生类型。Base*

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

于 2010-02-09T14:08:40.210 回答
1

如果没有继承关系,你可以使用什么样的指针?可以在指向不同类型对象的指针之间执行的唯一合法且合理的转换(忽略 const 转换)位于同一继承层次结构中。

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

此外,具有虚函数的类通常称为多态类,而多态类是唯一可以通过基类安全操作的类 ......因此从编程的角度来看,只为多态类型提供 RTTI 似乎很自然.

我的重点。

于 2010-02-09T13:40:08.917 回答
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 类必须至少有一个虚拟析构函数。不声明虚拟析构函数可能会导致内存泄漏,因为不会调用 Derived 析构函数。

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

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

于 2010-02-09T15:02:06.957 回答