我听说static_cast
函数应该优先于C风格或简单的函数式转换。这是真的?为什么呢?
答案 0 :(得分:583)
主要原因是经典C演员阵容不区分我们称之为static_cast<>()
,reinterpret_cast<>()
,const_cast<>()
和dynamic_cast<>()
的内容。这四件事完全不同。
static_cast<>()
通常是安全的。语言中有一个有效的转换,或者使它成为可能的适当构造函数。唯一一次有点危险的是当你被归入一个继承的阶级时;您必须通过语言外部的方式(如对象中的标志)确保该对象实际上是您声称它的后代。只要检查结果(指针)或考虑可能的异常(参考),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风格的演员阵容太难找到。在复杂的表达式中,很难看到C风格的演员表。在没有完整的C ++编译器前端的情况下编写一个需要定位C风格的演员表(例如搜索工具)的自动化工具几乎是不可能的。另一方面,搜索“static_cast&lt;”很容易或“reinterpret_cast&lt;”。
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风格的演员阵容更危险,而且要找到它们以确保它们是正确的更难。
答案 1 :(得分:109)
一个实用的提示:如果您打算整理项目,可以在源代码中轻松搜索static_cast关键字。
答案 2 :(得分:68)
简而言之:
static_cast<>()
为您提供编译时检查功能,C-Style 演员没有。static_cast<>()
可以很容易地被发现 C ++源代码中的任何地方;相比之下,C_Style演员更难发现。- 使用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型演员相比,静态演员阵容将允许 编译器检查指针和指针数据类型是什么 兼容,这允许程序员捕获这个错误 编译期间的指针赋值。
int *q = static_cast<int*>(&c); // compile-time error
了解更多信息:
What is the difference between static_cast<> and C style casting
和
Regular cast vs. static_cast vs. dynamic_cast
答案 3 :(得分:27)
问题不仅仅是使用枯萎的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。如果您真的想忘记类型,可以使用reintrepret_cast。只是将const抛出窗口就有const_cast。
他们只是让代码更明确,这样看起来你知道自己在做什么。
答案 4 :(得分:24)
static_cast
表示您不会意外const_cast
或reinterpret_cast
,这是一件好事。
答案 5 :(得分:7)
这是关于你想要施加多少类型安全性。
当您编写(bar) foo
(如果您还没有提供类型转换运算符,则相当于reinterpret_cast<bar> foo
)时,您告诉编译器忽略类型安全性,并按照它的说法进行操作。 / p>
当您编写static_cast<bar> foo
时,您要求编译器至少检查类型转换是否有意义,对于整数类型,请插入一些转换代码。
编辑2014-02-26
我在5年多前写过这个答案,我弄错了。 (见评论。)但它仍然得到了支持!
答案 6 :(得分:7)
请参阅Effective C++简介
答案 7 :(得分:4)
在一段代码中很容易错过C样式转换。 C ++风格的演员阵容不仅是更好的练习;它们提供了更大程度的灵活性。
reinterpret_cast允许指针类型转换的积分,但如果误用则可能不安全。
static_cast为数字类型提供了良好的转换,例如从枚举到整数或整数或浮点数或您对类型有信心的任何数据类型。它不执行任何运行时检查。
另一方面,dynamic_cast将执行这些检查,标记任何模糊的分配或转换。它只适用于指针和引用,并产生开销。
还有其他几个,但这些是你会遇到的主要原因。
答案 8 :(得分:3)
static_cast还可用于执行在类中明确定义的转换,以及执行基本类型之间的标准转换:
double d = 3.14159265;
int i = static_cast<int>(d);