【问题标题】:C++ Dynamic cast, is not polymorphic?C ++动态转换,不是多态的吗?
【发布时间】:2020-10-06 01:59:33
【问题描述】:

当我运行以下代码时:

#include <iostream>

class Shape{
public:
};

class Square:public Shape
{
public:
};

class Circle:public Shape
{
    double r;
public:
    void SetRadious(double r)
    {
        std::cout << "R value:" << this->r <<std::endl;
        this->r=r;
    }
};

int main() {
    Shape * s = new Square();
    Circle* c= dynamic_cast<Circle*>(s);
    c->SetRadious(3.0);
    return 0;
}

我收到一条错误消息:

“形状”不是多态的

我读到了,发现我需要写一些虚函数但是有两个问题:

1) 为什么这是必要的,需要一个虚函数是没有意义的。

2) 这种情况下很多人说我需要virtual d'tor 但是为什么默认的就不行了,默认的d'tor和默认的有什么区别呢?

【问题讨论】:

  • 这是有道理的,因为(子类型)多态性有一个成本,如果你不使用它,你就不想支付,如果你不使用它,你就不会使用它' t 有虚函数。
  • 请注意,即使具有多态性,正方形也不是圆形,因此 c 将是 nullptr,在取消引用时会导致 UB。

标签: c++ class inheritance polymorphism dynamic-cast


【解决方案1】:

类的层次结构,例如您所呈现的类,并不是多态开箱即用的。

dynamic_cast 要求层次结构是多态的。

使层次结构多态的最简单方法是制作基类virtual的析构函数:

class Shape {
    public:
        virtual ~Shape() = default;
};

这也带来了好处,您现在可以安全地在指向 Shape* 的指针上调用 delete,其中动态类型是子类之一。

这背后的基本原理是多态性引入了可能不需要的运行时开销。这也意味着您的类失去了一些类似 C 的属性,例如 trivial 类型。

注意,一旦你引入了这个虚拟析构函数,c 的值就在

Circle* c = dynamic_cast<Circle*>(s);

将是nullptrc-&gt;SetRadius(3.0); 的行为未定义。

【讨论】:

    【解决方案2】:

    1) 为什么需要这样做

    因为语言是这样说的。它是这么说的,因为这个限制可以让程序更快。

    需要一个虚函数是没有意义的。

    这对我来说很有意义。除非你有一个虚函数,否则我认为没有理由使用动态转换。 坦率地说,即使对于多态类,动态转换也很少有用。

    2) 在这种情况下,很多人说我需要 virtual d'tor 但是为什么默认的不会完全没问题,

    因为默认的不是虚拟的。

    您的示例泄漏了内存。如果您尝试通过执行delete s; 来修复泄漏,那么由于缺少虚拟析构函数,程序的行为将是未定义的。

    【讨论】:

    • OP 在泄漏之前会有 UB ;-)
    • @Jarod42 我没有看到 UB。由于dynamic_cast,该程序格式错误。但这并不能解释为什么需要虚拟析构函数。
    • 查看有问题的评论以查看 UB :)
    猜你喜欢
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 2020-09-13
    相关资源
    最近更新 更多