C++ 使用静态强制转换,因为动态强制转换失败。坏习惯?

C++ 使用静态强制转换,因为动态强制转换失败。坏习惯?,c++,dynamic-cast,static-cast,C++,Dynamic Cast,Static Cast,在我正在工作的一个项目中,我注意到一个动态的downcast失败了。快速代码检查确认特定对象实际上从未属于该类型。然而,我看到其他开发人员通过应用静态强制转换来强制执行相同的强制转换 在我看来,这是一种危险的方法,而且非常脆弱,如下面的例子所示。这通常不是一种糟糕的编程实践吗 class Base { public: Base(){ m_p = 0; } protected: int m_p; }; class Derived: public Base { public:

在我正在工作的一个项目中,我注意到一个动态的downcast失败了。快速代码检查确认特定对象实际上从未属于该类型。然而,我看到其他开发人员通过应用静态强制转换来强制执行相同的强制转换

在我看来,这是一种危险的方法,而且非常脆弱,如下面的例子所示。这通常不是一种糟糕的编程实践吗

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.
类基
{
公众:
Base(){m_p=0;}
受保护的:
国际货币政策;
};
派生类:公共基
{
公众:
派生(){m_arr=new int[1];}
void Add_A(){m_p+=2;}
void Add_B(){m_arr[0]+=3;}
私人:
int*m_arr;
};
Base*parent=newbase();
//显然失败->c_d为空
派生*c\u d=动态强制转换(父级);
派生*c_s=静态_转换(父级);
c_s->Add_A();//作品
c_s->Add_B();//崩溃,因为m_arr不存在。

使用
静态\u cast
因为
动态\u cast
失败不仅仅是一种不好的做法,它几乎保证了您的代码是不正确和不正确的。正如您在崩溃中演示的那样,您永远不应该这样做,而是应该实际修复代码;使用另一个cast不能解决任何问题

然而,有一个理由可以使用
static\u cast
,即
dynamic\u cast
的运行时成本。如果您完全确定
动态\u cast
始终会成功,则可以在性能约束要求的情况下,将其替换为
静态\u cast


(尽管在任何情况下,您都应该重新考虑为什么首先需要向下转换。此外,如果
动态\u cast
对于您的用例来说实际上太慢,那么很有可能您不希望从虚拟函数调用开始。)

它们所做的是调用未定义的行为

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

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

代价是每次更新编译器时,都要检查它是否正常工作。每次修改编译器标志时,都应该检查它是否有效。每次使用它时,你都应该检查它是否有效。两人相互重复

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

这不是理论上的危险。它发生在int溢出中,未签名到int未定义的行为被证明,分支被追溯消除


“它起作用”是第一步。它值得吗?

它调用未定义的行为,所以是的-这是一个糟糕的做法静态\u cast有未定义的行为。所以这种方法是彻底失败的。你没有一个
派生的
对象。无论施法多少都不会改变这一点。