【问题标题】:C++ static_cast vs dynamic_castC++ static_cast 与 dynamic_cast
【发布时间】:2017-01-12 17:20:28
【问题描述】:
#include <iostream>

class Base {
};

class Derived : public Base {
};

int main() {
    Base* bptr = new Derived();

    Derived* dptr = static_cast<Derived*>(bptr);

    std::cout << dptr << std::endl;
}

在上面的代码中,我应该使用 dynamic_cast 但我正在使用 static_cast 不正确。永远不应该使用 static_cast while 向下转换,因为编译器无法确定我们在做什么 正确投射。

为什么这不是编译错误?我正在使用 gcc 4.9.2。你们有吗 认为这是编译器中的错误,还是 C++ 标准允许这样的代码?

编辑:感谢您的回复。实际上,上面的基类是多态的 即它有虚函数,但我在这个例子中忽略了它们。我应该 已经在 Base 中加入了一个虚拟析构函数,以表明它 是多态的——我的错。

【问题讨论】:

  • 您可以将static_castBase* 更改为Derived*,但您是正确的,它不会执行任何类型检查。但是,如果您通过其他方式知道该指针确实指向Dervied 对象,它仍然很有用。如果Base* 实际上没有指向Derived*,那么由static_cast 产生的任何对Derived* 的解引用都会调用未定义的行为。
  • 实际上,这正是static_cast的用途;毕竟,对基类指针/引用的转换是隐式完成的。

标签: c++


【解决方案1】:

在上面的代码中,我应该使用dynamic_cast,但我错误地使用了static_caststatic_cast 不应该在向下转换时使用,因为编译器无法确定我们是否正确地进行转换。

具有讽刺意味的是,dynamic_cast 在这里实际上是格式错误的转换,因为您的类型不是多态的。

也就是说,static_cast 当然可以用来表示沮丧。编译器无法进行类型检查是正确的,但是在很多情况下,您有一个 Base* 并且知道它指向一个 Derived*,因此您可以手动进行强制转换。一种非常常见的情况是 CRTP:

template <class Derived>
class Base {
    Derived& self() { return *static_cast<Derived*>(this); }
    // ...
};


class Foo : Base<Foo> { ... };

Base&lt;T&gt;总是T,所以向下转换是安全的。

static_cast 相对于dynamic_cast 的优势在于static_cast 是免费的,但dynamic_cast 是昂贵的。 C++ 的口头禅是不要为你不需要的东西买单。

【讨论】:

    【解决方案2】:

    static_cast &lt; new_type &gt; ( expression )

    如果new_type 是指向某个类 D 的指针或引用,那么 expression 是指向其非虚基 B 的指针或引用, static_cast 执行向下转换。如果 B 是这种向下转换是病态的 模棱两可、不可访问或虚拟基地(或虚拟基地的基地) D. 这样的 static_cast 不进行运行时检查以确保 对象的运行时类型实际上是 D,并且只有在以下情况下才能安全使用 这个先决条件是通过其他方式来保证的,例如当 实现静态多态。可以通过以下方式完成安全的沮丧 dynamic_cast。

    Source(解释项2)

    【讨论】:

      【解决方案3】:

      您完全正确地使用了static_cast。你是对的,编译器在一般情况下可能不知道转换是否正确,但 static_cast 正是这种情况。

      您不能在此处使用dynamic_cast,因为该转换适用于多态类(具有虚拟成员函数的类)。这些类携带运行时信息;该信息允许代码在指向的对象的实际类型中选择该函数的正确实现。 对象中的这种类型信息可以被强制转换函数用来确定类型转换是否可能,然后确实正确地执行转换(这对于多重继承和虚拟继承可能很棘手)。

      没有虚函数的类,如您的示例类,不携带此运行时信息,并且dynamic_cast 不能用于转换为更派生的类型。 (它仍然可以用于转换为相同的类型或基类,即它可以用于实际上不需要转换的转换。)

      【讨论】:

        猜你喜欢
        • 2011-06-06
        • 2010-11-18
        • 2014-05-29
        • 1970-01-01
        • 2011-01-16
        • 2010-09-06
        • 1970-01-01
        相关资源
        最近更新 更多