使用静态转换,因为动态转换失败。不好的做法?

时间:2017-08-09 10:06:24

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

在我正在工作的项目中,我注意到动态向下转换失败了。快速代码检查证实,特定对象实际上从不属于那种类型。但是,我看到其他开发人员通过应用静态强制转换来强制执行此相同的强制转换。

在我看来,这是一种危险的方法,非常脆弱,如下例所示。这通常不是一个糟糕的编程习惯吗?

class Base
{
public:
    Base(){ m_p = 0; }
protected:
    int m_p;
};

class Derived: public Base
{
public:
    Derived(){ m_arr = new int[1]; }
    void Add_A() { m_p += 2; }
    void Add_B() { m_arr[0] += 3; }
private:
    int* m_arr;
};


Base* parent = new Base();

// obviously fails -> c_d is null
Derived* c_d = dynamic_cast<Derived*>(parent); 

Derived* c_s = static_cast<Derived*>(parent);
c_s->Add_A(); // works
c_s->Add_B(); // crashes, since m_arr does not exist.

2 个答案:

答案 0 :(得分:7)

使用static_cast ,因为 dynamic_cast失败不仅仅是不好的做法,它几乎可以保证您的代码不正确和破坏。正如您在崩溃中所展示的那样,您应该永远不要这样做并实际修复代码,使用其他强制转换无法解决您的任何问题。

然而, 是使用static_cast向下转发的原因,即dynamic_cast的运行时成本。如果绝对肯定 dynamic_cast 总是成功,您可以将其替换为性能限制要求的static_cast

(尽管在任何情况下你都应该重新考虑为什么你需要首先进行垂直转换。另外,如果dynamic_cast实际上对你的用例来说太慢了,你很可能不希望虚函数调用开头。)

答案 1 :(得分:3)

他们正在做的是调用未定义的行为。

在这种情况下,未定义的行为正在做他们想要的。在这个特定的来源。在这个特定的编译器。使用这些特定的编译器选项。

这将使继续这样做非常诱人。毕竟,它有效。

成本是每次更新编译器时,都应检查它是否有效。每次修改编译器标志时,都应该检查它是否有效。每次使用它时,都应该检查它是否有效。彼此相遇。

新版本的编译器(或新编译器,或现有编译器上的新标志)可以完美合理地合理地内联整个代码分支,请注意它确定性地包含未定义的行为,然后决定整个分支必须无法访问,并优化整个分支(有时包括测试)。

这不是理论上的危险。它发生在int overflow中,其中unsigned to int undefined behavior被证明并且分支被追溯删除。

&#34;它有效&#34;是第1步。这值得吗?