为什么使用static_cast <int>(x)而不是(int)x?
我听说static_cast
函数应该比C风格或简单的函数式风格更适合。 这是真的? 为什么?
主要原因是经典的C语言转换在我们所说的static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
和dynamic_cast<>()
之间没有区别。 这四件事情完全不同。
static_cast<>()
通常是安全的。 在语言中有一个有效的转换,或者一个合适的构造函数使之成为可能。 唯一有点危险的是,当你抛弃一个inheritance的类时, 你必须确保该对象实际上是你声称它的后裔,通过语言外部的手段(如对象中的一个标志)。 只要检查结果(指针)或者可能的exception被考虑(参考), dynamic_cast<>()
是安全的。
reinterpret_cast<>()
(或const_cast<>()
)总是危险的。 你告诉编译器:“相信我:我知道这看起来不像foo
(这看起来好像不可变),但它是”。
第一个问题是,几乎不可能知道哪一个会出现在C风格的演员中,而不会查看大量和分散的代码片断,并且知道所有的规则。
我们假设这些:
class CMyClass : public CMyBase {...}; class CMyOtherStuff {...} ; CMyBase *pSomething; // filled somewhere
现在,这两个编译方式是一样的:
CMyClass *pMyObject; pMyObject = static_cast<CMyClass*>(pSomething); // Safe; as long as we checked pMyObject = (CMyClass*)(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风格的演员太难find了。 在复杂的expression式中,很难看到C风格的演员。 编写一个自动化工具几乎是不可能的,如果没有一个完整的C ++编译器前端,需要定位C风格的types转换(例如search工具)。 另一方面,很容易search“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风格的风险更大,而且更难find它们,以确保它们是正确的。
一个实用的提示:如果您打算整理项目,您可以轻松search源代码中的static_cast关键字。
总之 :
static_cast<>()
给你一个编译时检查能力,C-stylestatic_cast<>()
不。static_cast<>()
可以很容易地在C ++源代码中的任何地方被发现; 相比之下,C_Style则更难以发现。- 使用C ++types转换,意图被传达得更好。
更多解释 :
静态转换执行兼容types之间的转换。 它类似于C风格的演员,但更具限制性。 例如,C风格的转换将允许一个整数指针指向一个字符。
char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes
由于这将导致指向分配内存的1个字节的4字节指针,写入该指针将导致运行时错误或将覆盖一些相邻的内存。
*p = 5; // run-time error: stack corruption
与C风格的转换相比,静态转换将允许编译器检查指针和指针数据types是否兼容,这允许程序员在编译期间捕获这个不正确的指针分配。
int *q = static_cast<int*>(&c); // compile-time error
阅读更多关于:
static_cast <>和C风格铸造有什么区别
和
经常投与vs. static_cast vs. dynamic_cast
这个问题比仅仅使用枯燥的static_cast或C风格的转换更大,因为使用C风格转换时会发生不同的事情。 C ++转型操作符旨在使这些操作更加明确。
在表面上,static_cast和C风格的转换看起来是相同的,例如,当将一个值转换为另一个值时:
int i; double d = (double)i; //C-style cast double d2 = static_cast<double>( i ); //C++ cast
这两个都将整数值转换为double。 但是,当使用指针时,事情变得更加复杂。 一些例子:
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的一个实例。但是如果你不知道在代码中的那一点实际上指向什么呢? (2)也许是完全合法的(你只想看看整数的一个字节),但也可能是一个错误,在这种情况下错误会很好,如(3)。 C ++转换运算符旨在通过在可能的情况下提供编译时或运行时错误来在代码中公开这些问题。
所以,对于严格的“价值铸造”,你可以使用static_cast。 如果你想运行时多态转换指针使用dynamic_cast。 如果你真的想忘记types,你可以使用reintrepret_cast。 而只是把const扔出窗口const_cast。
他们只是使代码更加明确,看起来你知道你在做什么。
static_cast
意味着你可以不小心const_cast
或reinterpret_cast
,这是一件好事。
- 允许在您的代码中使用grep或类似工具轻松find强制转换。
- 明确你正在做什么样的演员,并使编译器的帮助来执行它。 如果你只想抛弃const,那么你可以使用const_cast,它不允许你做其他types的转换。
- 强制转换本质上是丑陋的 – 作为程序员的你是在否定编译器通常如何处理你的代码。 你正在对编译器说:“我比你更清楚。” 既然如此,那么执行一个演员应该是一个适度的痛苦的事情,而且他们应该在你的代码中坚持下去是有意义的,因为他们可能是问题的根源。
请参阅有效的C ++简介
这是关于你想强加多lesstypes安全。
当你写(bar) foo
(相当于reinterpret_cast<bar> foo
如果你还没有提供一个types转换操作符的话),你告诉编译器忽略types安全性,并按照它的要求去做。
当你编写static_cast<bar> foo
你要求编译器至less检查types转换是否合理,对于整型来说,插入一些转换代码。
编辑2014-02-26
我在5年前写了这个答案,而且我弄错了。 (见评论)但它仍然起床!
除了操作指向类的指针之外,static_cast还可用于执行在类中明确定义的转换,以及在基本types之间执行标准转换:
double d = 3.14159265; int i = static_cast<int>(d);
C风格演员很容易错过一个代码块。 C ++风格的演员不仅是更好的练习, 他们提供了更大程度的灵活性。
reinterpret_cast允许指针types转换的积分,但是如果被滥用可能是不安全的。
static_cast为数字types提供了良好的转换,例如从枚举到整数或整数到浮点数或任何types的自信数据types。 它不执行任何运行时检查。
另一方面,dynamic_cast将执行这些检查,标记任何不明确的分配或转换。 它只能用于指针和引用,并且会产生开销。
还有一些其他的,但这些是你会遇到的主要的。