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!!!
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.
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>( i ); //C++ cast
这两种方法都是将整数值转换为双精度型。但是,当使用指针时,事情就变得更加复杂了。下面是一些例子:
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
9条答案
按热度按时间knpiaxh11#
主要原因是经典的C强制转换没有区分我们所说的
static_cast<>()
、reinterpret_cast<>()
、const_cast<>()
和dynamic_cast<>()
,这四种东西完全不同。static_cast<>()
通常是安全的。在语言中有一个有效的转换,或者一个适当的构造函数使它成为可能。唯一有点风险的时候是当你强制转换到一个继承的类;你必须通过外部的方法(比如对象中的标志)来确保对象实际上是你声称的后代.只要检查结果(指针)或者考虑可能的异常(引用),dynamic_cast<>()
是安全的.另一方面,
reinterpret_cast<>()
(或const_cast<>()
)总是很危险的。“相信我:我知道这看起来不像foo
(看起来好像它是不可变的),但它确实是”。第一个问题是,如果不查看大量分散的代码片段并了解所有规则,几乎不可能判断C样式强制转换中会出现哪一个。
让我们假设这些:
现在,这两个是以相同的方式编译的:
但是,让我们看看这段几乎相同的代码:
正如您所看到的,如果不了解所涉及的所有类,就没有简单的方法来区分这两种情况。
第二个问题是C风格的类型转换太难定位了。在复杂的表达式中,很难看到C风格的类型转换。如果没有一个成熟的C++编译器前端,几乎不可能编写一个需要定位C风格类型转换的自动化工具(例如搜索工具)。另一方面,搜索“static_cast〈”或“reinterpret_cast〈"很容易。
这意味着,不仅C风格的造型更危险,而且要找到它们以确保它们是正确的也要困难得多。
xzv2uavs2#
一个实用的建议:如果您计划整理项目,则可以在源代码中轻松搜索
static_cast
关键字。v8wbuo2f3#
简而言之:
static_cast<>()
为您提供了编译时检查功能,而C-Style类型转换则没有。static_cast<>()
可以在C源代码中的任何地方轻松找到;相比之下,C_Style强制转换更难发现。1.使用C类型转换可以更好地表达意图。
更多说明:
静态强制转换执行兼容类型之间的转换。它类似于C样式强制转换,但限制性更强。例如,C样式强制转换允许整数指针指向char。
由于这会导致一个4字节指针指向分配内存的1字节,因此写入此指针将导致运行时错误或覆盖某些相邻内存。
与C样式强制转换相反,静态强制转换允许编译器检查指针和被指针对象数据类型是否兼容,这允许程序员在编译期间捕获这种不正确的指针赋值。
阅读更多信息:
What is the difference between static_cast<> and C style casting
以及
常规强制转换、静态强制转换和动态强制转换
oxosxuxt4#
问题不仅仅在于使用
static_cast<>
还是C风格的强制转换,因为使用C风格的强制转换时会发生不同的事情。C++强制转换操作符旨在使这些不同的操作更加明确。在表面上,
static_cast<>
和C风格的强制转换看起来是一样的,例如,当将一个值强制转换为另一个值时:这两种方法都是将整数值转换为双精度型。但是,当使用指针时,事情就变得更加复杂了。下面是一些例子:
在这个例子中,(1)可能是可以的,因为A指向的对象实际上是B的一个示例。但是如果在代码中不知道
a
实际指向什么呢?(2)可能是完全法律的的(您只想查看整数的一个字节),但也可能是一个错误,在这种情况下,出现一个错误会更好,如(3)。
C++强制转换运算符旨在通过在可能的情况下提供编译时或运行时错误来暴露代码中的这些问题。
因此,对于严格的“值强制转换”,你可以使用
static_cast<>
;如果你想在运行时对指针进行多态强制转换,可以使用dynamic_cast<>
;如果你真的不想考虑类型,可以使用reintrepret_cast<>
;如果你想把const
抛出窗口,可以使用const_cast<>
。它们只是使代码更显式,这样看起来你知道你在做什么。
gcxthw6b5#
static_cast
意味着您不会意外地使用const_cast
或reinterpret_cast
,这是一件好事。whhtz7ly6#
1.允许使用grep或类似工具在代码中轻松找到强制转换。
1.明确你正在做什么类型的转换,并在编译器的帮助下强制执行。如果你只想摆脱常量,那么你可以使用const_cast,它不允许你做其他类型的转换。
1.强制转换本质上是丑陋的--作为程序员,您否决了编译器通常如何处理您的代码。您对编译器说,“我比您更了解。”在这种情况下,执行强制转换应该是一件比较痛苦的事情,并且它们应该在您的代码中突出,因为它们很可能是问题的来源。
参见Effective C++简介
3df52oht7#
这是关于你想要施加多大程度的类型安全。
当你写
(bar) foo
(如果你没有提供类型转换操作符,它就等同于reinterpret_cast<bar> foo
)时,你告诉编译器忽略类型安全,并且按照它被告知的去做。在编写
static_cast<bar> foo
时,您要求编译器至少检查类型转换是否有意义,并且对于整型,插入一些转换代码。编辑日期:2014年2月26日
这个答案是我5年多前写的,我写错了。(看评论)但它仍然得到了支持票!
ifsvaxew8#
C风格的类型转换在代码块中很容易被忽略。C++风格的类型转换不仅是更好的实践;它们提供了更大程度的灵活性。
reinterpret_cast允许从整型到指针类型的转换,但是如果误用,可能会不安全。
static_cast为数值类型提供了很好的转换,例如从as enums到int,或者从int到float,或者任何你确信的数据类型。它不执行任何运行时检查。
另一方面,dynamic_cast将执行这些检查,标记任何不明确的赋值或转换。它只对指针和引用起作用,并且会产生开销。
还有一些其他的,但这些是你会遇到的主要的。
qojgxg4l9#
static_cast除了操作指向类的指针外,还可以用于执行类中显式定义的转换,以及执行基本类型之间的标准转换: