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

Use static cast because dynamic cast fails. Bad practice?

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

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

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.

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

但是, 有理由使用 static_cast 进行向下转换,即 dynamic_cast 的运行成本。如果您绝对确定 dynamic_cast 总是 成功,您可以用 static_cast 替换它,其中性能受限要求。

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

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

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

这会让人很想继续这样做。毕竟,它有效。

代价是每次更新编译器时,您都应该检查它是否正常工作。每次修改编译器标志时,都应该检查它是否有效。每次使用它时,都应该检查它是否有效。互相倍数。

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

这不是理论上的危险。它发生在 int 溢出中,其中证明了 unsigned 到 int 未定义的行为并且追溯地消除了分支。

"It works" 是第 1 步。值得吗?