提问人:Tommy Herbert 提问时间:9/20/2008 最后编辑:Jan SchultkeTommy Herbert 更新时间:10/7/2023 访问量:429013
为什么使用 static_cast<T>(x) 而不是 (T)x?
Why use static_cast<T>(x) instead of (T)x?
答:
static_cast,除了操作指向类的指针之外,还可用于执行类中显式定义的转换,以及执行基本类型之间的标准转换:
double d = 3.14159265;
int i = static_cast<int>(d);
评论
static_cast<int>(d)
(int)d
(int)d
int{d}
()
int i{d}
int i = (int)d
static_cast
(C)casts
cout
static_cast
意味着你不能偶然或,这是一件好事。const_cast
reinterpret_cast
评论
这是关于你想施加多少类型安全。
当你编写时(这相当于你没有提供类型转换运算符),你是在告诉编译器忽略类型安全,而只是按照它的指示去做。(bar) foo
reinterpret_cast<bar> foo
当你编写时,你要求编译器至少检查类型转换是否有意义,对于整型类型,插入一些转换代码。static_cast<bar> foo
编辑 2014-02-26
我在 5 年多前写了这个答案,但我弄错了。(请参阅注释。但它仍然会得到点赞!
评论
static_cast<bar>(foo)
reinterpret_cast<bar>(foo)
一个实用的提示:如果你打算整理项目,你可以轻松地在源代码中搜索关键词。static_cast
评论
int
主要原因是经典的 C 强制转换没有区分我们所说的 、、 和 。这四件事是完全不同的。static_cast<>()
reinterpret_cast<>()
const_cast<>()
dynamic_cast<>()
A 通常是安全的。语言中存在有效的转换,或者适当的构造函数使之成为可能。唯一有点冒险的时候是当你扔到一个继承的类时;您必须确保该对象实际上是您声称的后代,通过语言外部的方式(如对象中的标志)。只要检查结果(指针)或考虑可能的异常(引用),A 就是安全的。static_cast<>()
dynamic_cast<>()
另一方面,A(或A)总是危险的。你告诉编译器:“相信我:我知道这看起来不像一个(这看起来好像它不可变),但它是”。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
dynamic_cast
static_cast
dynamic_cast
static_cast
dynamic_cast
static_cast
reinterpret_cast
*(destination_type *)&
int
int
static_cast<int>
(int)
int
dynamic_cast
v
float
(int)v
static_cast<int>(v)
float*
(int)v
reinterpret_cast<int>(v)
static_cast<int>(v)
这个问题比仅仅使用 Whether 或 C 型铸造更重要,因为使用 C 型铸造时会发生不同的事情。C++ 强制转换运算符旨在使这些不同的操作更加明确。static_cast<>
从表面上看,C样式的强制转换似乎是一回事,例如,当将一个值转换为另一个值时:static_cast<>
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
在此示例中,(1) 可能没问题,因为 A 指向的对象实际上是 B 的实例。但是,如果你在代码中不知道实际指向什么怎么办?a
(2) 可能是完全合法的(你只想看整数的一个字节),但它也可能是一个错误,在这种情况下,错误会很好,比如 (3)。
C++ 强制转换运算符旨在通过尽可能提供编译时或运行时错误来公开代码中的这些问题。
因此,对于严格的“价值转换”,您可以使用 .如果要对指针进行运行时多态转换,请使用 .如果你真的想忘记类型,你可以使用 .只是扔出窗外有.static_cast<>
dynamic_cast<>
reintrepret_cast<>
const
const_cast<>
它们只是使代码更加明确,以便看起来您知道自己在做什么。
C 样式的强制转换在代码块中很容易被遗漏。C++ 样式的强制转换不仅是更好的实践;它们提供了更大程度的灵活性。
reinterpret_cast允许对指针类型进行积分转换,但如果使用不当,则可能不安全。
static_cast为数值类型提供了良好的转换,例如从枚举到整数或整数到浮点数或您确信类型的任何数据类型。它不执行任何运行时检查。
另一方面,dynamic_cast将执行这些检查,标记任何模棱两可的分配或转换。它仅适用于指针和引用,并会产生开销。
还有其他几个,但这些是您将遇到的主要问题。
- 允许在以下位置轻松找到石膏 使用 grep 或类似代码的代码 工具。
- 明确说明哪种 你正在做的演员,并且引人入胜 编译器帮助执行它。 如果你只想抛弃 const-ness,那么你可以使用 const_cast,这不会让你 进行其他类型的转换。
- 演员本质上是丑陋的——你作为 程序员正在推翻 编译器通常会处理你的 法典。你是在对 编译器,“我比你更清楚。 既然如此,这是有道理的 表演演员应该是 做中度痛苦的事情,以及 他们应该在你的 代码,因为它们是可能的来源 的问题。
请参阅有效的 C++ 简介
评论
简而言之:
static_cast<>()
给你一个编译时检查能力,C-Style 演员不会。static_cast<>()
可以很容易地被发现 C++ 源代码中的任何位置;相比之下,C_Style演员更难被发现。- 使用 C++ 强制转换可以更好地传达意图。
更多说明:
静态强制转换在兼容类型之间执行转换。它 类似于 C 型演员表,但限制性更强。例如 C 样式强制转换将允许整数指针指向字符。
char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes
由于这会导致一个 4 字节指针指向分配的 1 个字节 内存,写入此指针将导致运行时错误或 将覆盖一些相邻的内存。
*p = 5; // run-time error: stack corruption
与 C 样式强制转换相比,静态强制转换将允许 编译器来检查指针和指针数据类型是否 compatible,这允许程序员捕捉到这个不正确的 编译期间的指针分配。
int *q = static_cast<int*>(&c); // compile-time error
阅读更多:
static_cast<> 和 C 风格铸造与常规铸造
与
static_cast 与 dynamic_cast 有什么区别
评论
static_cast<>()
static_cast<uint##>()
(uint##)
always
(uint32_t)(uint8_t)
0xFF &
上一个:直接铸造与“作为”操作员?
评论