关于c ++:为什么使用static_cast< int>(x)代替(int)x?

Why use static_cast<int>(x) instead of (int)x?

我听说static_cast函数应该优先于C样式或简单的函数样式转换。这是真的吗?为什么?


主要原因是经典的C型铸造没有区别于我们称之为static_cast<>()reinterpret_cast<>()const_cast<>()dynamic_cast<>()。这四件事完全不同。

static_cast<>()通常是安全的。语言中有一个有效的转换,或者一个适当的构造函数使其成为可能。唯一有点危险的时候是当您将对象下放到继承的类中时;您必须通过语言外部的方式(如对象中的标志),确保对象实际上是您声称的后代。只要检查结果(指针)或考虑到可能的异常(参考),dynamic_cast<>()是安全的。

另一方面,reinterpret_cast<>()const_cast<>()总是危险的。你告诉编译器:"相信我:我知道这看起来不像一个foo,但它是可变的。"

第一个问题是,如果不看大而分散的代码片段,不知道所有规则,几乎不可能知道哪一个将出现在C样式的演员表中。

假设如下:

1
2
3
4
class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

现在,这两者的编译方式相同:

1
2
3
4
5
6
CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked

pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
                                     // Safe; as long as we checked
                                     // but harder to read

但是,让我们看看这个几乎相同的代码:

1
2
3
4
5
6
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert

pOther = (CMyOtherStuff*)(pSomething);            // No compiler error.
                                                  // Same as reinterpret_cast<>
                                                  // and it's wrong!!!

正如您所看到的,在不了解所有涉及的类的情况下,区分这两种情况并非易事。

第二个问题是C型铸件太难定位。在复杂表达式中,很难看到C样式的强制转换。几乎不可能编写一个自动化工具,它需要定位C风格的铸件(例如一个搜索工具),而不需要一个完整的C++编译器前端。另一方面,很容易搜索"static-cast<"或"reinterpret-cast<"。

1
2
3
4
5
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
      // No compiler error.
      // but the presence of a reinterpret_cast<> is
      // like a Siren with Red Flashing Lights in your code.
      // The mere typing of it should cause you to feel VERY uncomfortable.

这意味着,不仅C型的石膏更危险,而且很难找到所有的石膏来确保它们是正确的。


一个实用的提示:如果你打算整理项目,你可以很容易地在源代码中搜索静态的强制转换关键字。


In short:

  • static_cast<>() gives you a compile time checking ability, C-Style
    cast doesn't.
  • static_cast<>() can be spotted easily
    anywhere inside a C++ source code; in contrast, C_Style cast is harder to spot.
  • Intentions are conveyed much better using C++ casts.
  • More Explanation:

    The static cast performs conversions between compatible types. It
    is similar to the C-style cast, but is more restrictive. For example,
    the C-style cast would allow an integer pointer to point to a char.

    1
    2
    char c = 10;       // 1 byte
    int *p = (int*)&amp;c; // 4 bytes

    Since this results in a 4-byte pointer pointing to 1 byte of allocated
    memory, writing to this pointer will either cause a run-time error or
    will overwrite some adjacent memory.

    1
    *p = 5; // run-time error: stack corruption

    In contrast to the C-style cast, the static cast will allow the
    compiler to check that the pointer and pointee data types are
    compatible, which allows the programmer to catch this incorrect
    pointer assignment during compilation.

    1
    int *q = static_cast<int*>(&amp;c); // compile-time error

    阅读更多信息:静态铸造和C型铸造的区别是什么?和常规铸造vs.静态铸造vs.动态铸造


    这个问题比仅仅使用威瑟静态类型转换或C类型转换要严重,因为使用C类型转换时会发生不同的事情。C++铸造操作符旨在使这些操作更加显式。

    在表面上,静态类型转换和C样式转换看起来是相同的,例如,将一个值转换为另一个值时:

    1
    2
    3
    int i;
    double d = (double)i;                  //C-style cast
    double d2 = static_cast<double>( i );  //C++ cast

    这两种方法都将整数值强制转换为double。但是,当使用指针时,事情会变得更复杂。一些例子:

    1
    2
    3
    4
    5
    6
    7
    8
    class A {};
    class B : public A {};

    A* a = new B;
    B* b = (B*)a;                                  //(1) what is this supposed to do?

    char* c = (char*)new int( 5 );                 //(2) that weird?
    char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error

    在这个例子(1)中,也许可以,因为a指向的对象实际上是b的一个实例。但是,如果您在代码中不知道a实际指向的是什么呢?(2)也许完全合法(您只想查看整数的一个字节),但在这种情况下,它也可能是一个错误,在这种情况下,错误会很好,如(3)。C++铸造运算符旨在通过提供编译时间或运行时错误在可能的情况下在代码中公开这些问题。

    因此,对于严格的"值强制转换",可以使用静态强制转换。如果要对指针进行运行时多态强制转换,请使用动态强制转换。如果你真的想忘记类型,你可以使用reintrepret-cast。把警察扔出窗外就是警察。

    它们只是使代码更显式,这样看起来您就知道自己在做什么了。


    static_cast是指你不能不小心的const_castreinterpret_cast这是件好事。


  • 允许轻松找到铸件使用grep或类似代码工具。
  • 明确什么类型你正在做的演员,和迷人的编译器帮助实现它。如果你只想抛弃康斯,那你可以用警察局,不允许你进行其他类型的转换。
  • 演员表天生就很难看——你就像一个程序员正在否决编译器通常会处理代码。你是在说编译器:"我比你更了解。"既然如此,这是有道理的演出应该是做一件中度疼痛的事情,以及他们应该在你的代码,因为它们可能是源代码问题。
  • 见有效C++介绍


    这是关于你想要强加多少类型的安全性。

    当您编写(bar) foo时(如果您没有提供类型转换运算符,则相当于reinterpret_cast foo时),您告诉编译器忽略类型安全性,并按照它的指示进行操作。

    当您编写static_cast foo时,您要求编译器至少检查类型转换是否有意义,对于整型,还需要插入一些转换代码。

    编辑2014-02-26

    5年前我写了这个答案,但我错了。(见评论)但它仍然得到了支持!


    C样式的强制转换在代码块中很容易丢失。C++样式转换不仅是更好的实践,还提供了更大程度的灵活性。

    reinterpret_cast允许积分到指针类型的转换,但如果使用不当,则可能不安全。

    静态类型转换为数值类型提供了良好的转换,例如从as-enum到ints或ints到float或任何您确信类型的数据类型。它不执行任何运行时检查。

    另一方面,动态类型转换将执行这些检查,标记任何不明确的分配或转换。它只在指针和引用上工作,并产生开销。

    还有一些其他的,但这些是你会遇到的主要的。


    除了操作指向类的指针之外,静态类型转换还可以用于执行在类中显式定义的转换,以及在基本类型之间执行标准转换:

    1
    2
    double d = 3.14159265;
    int    i = static_cast<int>(d);