【问题标题】:Dynamic_cast not showing the right object typeDynamic_cast 未显示正确的对象类型
【发布时间】:2017-08-16 21:42:43
【问题描述】:

我花了很多时间试图弄清楚为什么我的代码在运行后显示“Derived3”,但我根本无法理解。从我在许多帖子中读到的内容来看,dynamic_cast 应该以某种方式说明指针(在本例中为 b)是否(在本例中)Derived2。但是,它通过了条件,当它应该从 Derived2 类中打印出 display() 函数时,它奇怪地显示了 Derived3 类中的函数。我只是想知道为什么程序显示“Derived 3”而不是不显示任何内容,因为 b 指针显然没有指向 Derived2 对象。

#include <iostream>

using namespace std;

class Base
{
    int b;
    public:
    virtual void display()
    {
        cout<<"Base"<<endl;
    }
};

class Derived: virtual public Base{
public:
    void display()
    {
        cout<<"Derived"<<endl;
    }
};

class Derived2: virtual public Base{
public:
    void display()
    {
        cout<<"Derived 2"<<endl;
    }
};

class Derived3:public Derived,public Derived2{
public:
    void display()
    {
        cout<<"Derived 3"<<endl;
    }
};

int main()
{
    Base *b = new Derived3();
    Derived2 *aux = dynamic_cast<Derived2*>(b);
    if(aux)
    {
        aux->display();
    }

    return 0;
}

不过,稍微修改一下代码后,它就可以正常工作了。

#include <iostream>

using namespace std;

class Base
{
    int b;
    public:
    virtual void display()
    {
        cout<<"Base"<<endl;
    }
};

class Derived: public Base{
public:
    void display()
    {
        cout<<"Derived"<<endl;
    }
};

class Derived2: public Base{
public:
    void display()
    {
        cout<<"Derived 2"<<endl;
    }
};

class Derived3:public Base{
public:
    void display()
    {
        cout<<"Derived 3"<<endl;
    }
};

int main()
{
    Base *b = new Derived3();
    Derived2 *aux = dynamic_cast<Derived2*>(b);
    if(aux)
    {
        aux->display();
    }

    return 0;
}

【问题讨论】:

  • 附带说明,如果您不想要“Is-a”关系,请使用组合而不是继承。

标签: c++ dynamic-cast


【解决方案1】:

继承是一种“Is-a”关系。

每个Derived 都是DerivedBase。按照这种模式,每个Derived3 同时是一个Derived3、一个Derived2、一个Derived 和一个Base

因此,该演员阵容失败是没有意义的。

输出最终是对Derived2* 的普通虚函数调用的结果。这与最简单的继承示例没有什么不同,例如在这个 sn-p 中:

#include <iostream>

struct A {
    virtual void fun() const {
        std::cout << 'A';
    }
};

struct B : A {
    void fun() const {
        std::cout << 'B';
    }
};

int main () {
    const A &a = B();
    a.fun();            // prints 'B'
}

如果您有指向某个基类的指针或引用,则虚函数调用将解析为调用它的对象的实际类型。在您的情况下,这是一个 Derived2* 指向 Derived3 类型的子类,因此在后者中查找该函数。

请记住,dynamic_cast 只会改变指针的类型,而不是它指向的对象的类型!

【讨论】:

  • (另外,一如既往,因为标准是这样说的,但我猜这不是问题的重点。)
  • 感谢您的回答,但我仍然不明白为什么它显示 Derived 3。我知道每个 Derived 3 都是派生 2、派生和基础,但我不明白为什么 b不是派生 2 的指针从派生 3 类调用 display 方法。
  • @TheDarkKnight 编辑了一些额外的示例和解释,有帮助吗?
  • 这里已经很晚了,我真的在这个问题上花了这么长时间,我无法真正集中注意力......我理解你在示例中写的内容,但基于这个原则,我的代码不应在屏幕上显示任何内容,我在发布的第二个代码中对其进行了解释。它在那里工作,因为它应该是。我猜这与修复了钻石问题但与 dynamic_cast 混淆的虚拟继承有关...
  • @TheDarkKnight 在您的第二段代码中,Derived3 不继承自 Derived2,因此强制转换失败。更改后Derived3 不再是Derived2
【解决方案2】:

但是,它通过了条件,当它应该从 Derived2 类中打印出 display() 函数时,它奇怪地显示了 Derived3 类中的函数。

这是因为动态调度。请记住 display() 被声明为 virtual 成员函数。它仍然是所有派生类的virtual 成员函数。

即使您将指针从Base* 转换为Derived*,底层对象仍然是Derived3。因此,动态调度机制调用Derived3::display()

Derived3::display() 如果你使用也会被调用:

Base *b = new Derived3();
b->display();

【讨论】:

  • @R Sahu 是的,既然 display() 是一种虚方法,程序调用 *b 指针指向的方法不应该是正常的,为什么似乎是 Derived2?如果我问它是否是 Derived 2,为什么该对象仍被视为 Derived 3?
  • @TheDarkKnight,它是Derived2,也因为它是Derived3。底层对象仍然是Derived3 对象。使用dynamic_cast 获取对象的Derived2* 不会改变这一点。
  • @R Sahu 所以你说的是基于继承的设计,即使它们是 5,6,7 每个这样的派生类:Derived 1 from Base, Derived 2 from Derived 1, Derived 3 from Derived 2 等等。在这种情况下,底层对象将始终是最后一个 Derived 7?我的意思是,只有当我有多个从同一个基础派生的类时,dynamic_cast 才能按我的意愿工作,例如:从 Base 派生,从 Base 派生 1 等。因为那是显示函数打印出应有的答案的时候。
  • @TheDarkKnight,底层对象将始终是您构造的类型。如果您使用Base* b = new Derived6;,则底层对象将为Derived6。仅仅因为Derived7 派生自Derived6,并不意味着构造的对象将始终是Derived7 类型。
猜你喜欢
  • 2017-01-11
  • 1970-01-01
  • 2021-12-23
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-26
  • 2019-09-10
  • 1970-01-01
相关资源
最近更新 更多