协慌网

登录 贡献 社区

为什么使用 static_cast <int>(x)而不是(int)x?

我听说static_cast函数应该比 C 样式或简单的函数样式转换更可取。这是真的?为什么?

答案

主要原因是经典的 C 强制转换在我们所谓的static_cast<>()reinterpret_cast<>()const_cast<>()dynamic_cast<>()之间没有区别。这四件事完全不同。

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

reinterpret_cast<>() (或const_cast<>() )始终很危险。您告诉编译器:“相信我:我知道这看起来不像foo (看起来好像是不可变的),但是确实如此。”

第一个问题是,在不查看大量分散代码并知道所有规则的情况下,几乎不可能分辨出将在 C 样式转换中发生哪一个。

让我们假设这些:

class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

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

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

但是,让我们看一下几乎相同的代码:

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 <”。

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 风格的强制转换更加危险,而且要确保它们正确无误地查找它们要困难得多。

一个实用的技巧:如果您打算整理项目,则可以在源代码中轻松搜索 static_cast 关键字。

简而言之

  1. static_cast<>()为您提供了编译时检查功能,而 C-Style 强制转换则没有。
  2. static_cast<>()可以很容易地在 C ++ 源代码中的任何位置发现;相反,很难发现 C_Style 强制转换。
  3. 使用 C ++ 强制转换可以更好地传达意图。

更多说明

静态类型转换在兼容类型之间执行转换。它类似于 C 样式的强制类型转换,但更具限制性。例如,C 样式强制转换将允许整数指针指向 char。

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

由于这会导致一个 4 字节的指针指向分配的内存的 1 字节,因此对该指针进行写入将导致运行时错误或覆盖某些相邻的内存。

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

与 C 样式强制转换相反,静态强制转换将允许编译器检查指针和 pointee 数据类型是否兼容,从而允许程序员在编译期间捕获此错误的指针分配。

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

阅读更多内容:
static_cast <> 和 C 样式转换之间有什么区别

常规投放与 static_cast 与 dynamic_cast