【问题标题】:static cast working and dynamic cast segfaults静态铸造工作和动态铸造段错误
【发布时间】:2021-08-27 11:56:10
【问题描述】:

以下代码可以正常编译:

#include<iostream>

class Base {
    protected:
        int _a;

    public: 
        virtual ~Base()=default;
        Base(int a) : _a{a} {};

        int getit() const { return _a; }
};

class Derived : public Base {
    public:

        Derived(int a) : Base{a} {};
        int get2() const { return 2*this->_a; }
};

int main() {
    Base D{2};
    auto* ptr = &D;
    auto* ptr2 = static_cast<Derived*>(ptr);


    std::cout << ptr2->get2() << std::endl;
}

输出

4

如果我将static_cast 更改为dynamic_cast,则会出现段错误。

我的问题: 使用static_cast 强制转换为不添加任何数据成员的派生类是否安全?

【问题讨论】:

  • 未定义行为的一个令人讨厌的事情是,有时它可能会起作用。这并不意味着它确实如此。
  • ptr 和 ptr2 均未指向 Derived 对象。因此强制转换是错误的,取消引用指针会导致未定义的行为。

标签: c++ dynamic-cast static-cast


【解决方案1】:

使用 static_cast 向下转换为派生类是否安全

仅当对象的动态类型是派生类时(或者派生类是动态类型的基础,甚至进一步派生)。向上转换也是安全的,但这种转换也是隐式的。

如果您不知道情况是否如此,并且 - 如示例中那样 - 当您知道情况并非如此时,这绝对不安全,示例程序的行为是未定义的。使用dynamic_cast 是安全的,但不检查它是否返回null,然后通过该null 进行间接处理是不安全的。

总之,这是安全的:

if (auto* ptr2 = dynamic_cast<Derived*>(ptr)) {
    std::cout << ptr2->get2() << std::endl;
} else {
    std::cout << "It's not Derived :(" << std::endl;
}

也就是说,如果您认为需要dynamic_cast,那么您可能应该重新考虑设计。您可能应该改用虚函数。示例:

class Base {
protected:
    int _a;

public: 
    virtual ~Base()=default;
    Base(int a) : _a{a} {};

    virtual int getit() const { return _a; }
};

class Derived : public Base {
public:
    using Base::Base;
    int getit() const override { return 2*this->_a; }
};

【讨论】:

    【解决方案2】:

    在这种情况下,使用错误类型的演员会让您感到悲伤。如 cmets 中所述,ptr2 未指向有效的 Derived 对象。

    因此,使用您的static_cast,您会看到未定义的行为;这恰好给出了一个明显“正确”的答案,但你永远不能依赖它。

    但是,使用dynamic_cast 将导致ptr2 具有nullptr 值(因为ptr 指向的对象不是Derived);您尝试取消引用 nullptr 会导致您的程序崩溃(通常会这样)。

    但请注意,使用dynamic_cast 可以让您轻松检查该转换是否成功(通过测试nullptr 的返回值); static_cast 没有给你这个选项。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-29
      • 2020-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多