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

发布于 2024-08-20 09:43:56 字数 868 浏览 7 评论 0原文

据我了解,动态转换与静态转换的不同之处在于它对 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 不允许进行基到派生的转换。

这段代码中的第二次转换将产生编译错误,因为除非基类是多态的, cplusplus.com/doc/tutorial/typecasting/" rel="nofollow noreferrer">http://www.cplusplus.com/doc/tutorial/typecasting/

As I understand it, what makes dynamic cast different from a static cast is its use of RTTI, and the fact that it fails if the dynamic type of a variable- when casting from base to derived- does not fit. But why does the class have to be polymorphic for that to be done if we have the RTTI anyway?

EDIT: Since there was some confusion about the use of the word "polymorphic", here's the entry in cplusplus.com that prompted me to ask this:

dynamic_cast can be used only with pointers and references to objects. Its purpose is to ensure that the result of the type conversion is a valid complete object of the requested class.

Therefore, dynamic_cast is always successful when we cast a class to one of its base

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 

The second conversion in this piece of code would produce a compilation error since base-to-derived conversions are not allowed with dynamic_cast unless the base class is polymorphic.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

甩你一脸翔 2024-08-27 09:43:56

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

RTTI information is available only for class with a virtual member. (The assumed implementation is that the vtable contains what it needed for dynamic_cast to work; you could work out other schemes, but all would need a type identifier in the object, so why not use the vptr?)

酒解孤独 2024-08-27 09:43:56

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

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

我认为,如果相关类型不提供任何动态类型信息,dynamic_cast 无法确定向下转换的有效性。对于非多态 Base,Base* 就是这样,它没有可以在运行时检查的动态最派生类型。

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

Run-time type identification is involved. dynamic_cast has to check the validity of down-casting at run-time (and return a NULL pointer / throw an exception if the cast is to an unsuitable type).

The standard states that with polymorphic types, typeid refers to the dynamic type of the object (most derived), for other types it refers to the static type of the object.

I suppose dynamic_cast cannot determine the validity of the down-cast, if the type in question doesn't provide any dynamic type information. With a non-polymorhic Base, a Base* is just that, it doesn't have a dynamic most derived type that can be checked at run-time.

The validity of the up-cast, on the other hand, can be determined statically at compile-time.

绅刃 2024-08-27 09:43:56

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

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

此外,还有一个带有虚拟的类
函数通常被称为
多态类和多态
类是唯一可以
通过基类安全地操作

...从编程的角度来看,
因此似乎很自然地提供
RTTI 仅适用于多态类型。

我的强调。

What sort of pointer could you use if there was no inheritance relationship? The only legal and sensible casts that can be performed between pointers to objects of different types (ignoring const casts) are within the same inheritance hierarchy.

Edit: To quote BS from the D&E book on dynamic_cast, section 14.2.2.2:

Further, a class with virtual
functions is often called a
polymorphic class and polymorphic
classes are the only ones that can be
safely manipulated via a base class

... From a programming point of view,
it therefore seems natural to provide
RTTI for polymorphic types only.

My emphasis.

淡莣 2024-08-27 09:43:56
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;

}

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

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

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

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;

}

The Base class has to have at the very least a virtual destructor. Not declaring a virtual destructor
may introduce memory leaks because the Derived destructor will not be called.

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

If RTTI is switched on, this line of code will result in a null pointer. If RTTI is not enabled the line results in a runtime error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文