我听说该static_cast
函数应该比C样式或简单的函数样式转换更好。这是真的?为什么?
我听说该static_cast
函数应该比C样式或简单的函数样式转换更好。这是真的?为什么?
Answers:
主要的原因是,经典的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
用于强制继承层次结构,而应使用dynamic_cast
。这将返回空指针或有效指针。
static_cast
在这种情况下使用的注意事项。dynamic_cast
也许更安全,但这并不总是最好的选择。有时您确实知道,通过编译器不透明的方式,指针指向给定的子类型,并且a static_cast
更快。至少在某些环境中,dynamic_cast
需要可选的编译器支持和运行时成本(启用RTTI),并且您可能不希望仅为执行两项检查就启用它。C ++的RTTI只是该问题的一种可能解决方案。
static_cast
。与C等效的reinterpret_cast
是*(destination_type *)&
,即获取对象的地址,将该地址转换为指向其他类型的指针,然后取消引用。除字符类型或某些结构类型的情况下,其为C定义这个构建体的行为,它通常导致在C.未定义的行为
int
(和int
单独使用),为什么将static_cast<int>
vs. (int)
用作唯一的好处似乎在于类变量和指针。要求您对此进行详细说明。
int
dynamic_cast
不适用,但是所有其他原因仍然有效。例如:假设v
一个函数参数声明为float
,(int)v
则为static_cast<int>(v)
。但是,如果你改变参数float*
,(int)v
悄悄地成为reinterpret_cast<int>(v)
虽然static_cast<int>(v)
是非法的,由编译器正确捕获。
一个实用的技巧:如果您打算整理项目,则可以在源代码中轻松搜索static_cast关键字。
int
参数的函数声明。
简而言之:
static_cast<>()
为您提供了编译时检查功能,而C样式强制转换则没有。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
阅读更多内容:
static_cast <>和C样式转换
与常规转换与static_cast与dynamic_cast有什么区别?
static_cast<>()
。我的意思是,有时候是这样,但是在大多数情况下(尤其是在基本整数类型上),它只是非常可怕且不必要地冗长。例如:此函数交换32位字的字节。使用static_cast<uint##>()
强制转换几乎是不可能阅读的,但是使用强制转换很容易理解(uint##)
。代码图片: imgur.com/NoHbGve
always
。(但是大多数时候是)在某些情况下,c样式强制转换的可读性更高。这就是c样式转换仍然有效并在c ++ imho中发挥作用的原因之一。:)顺便说一句,这是一个很好的例子
(uint32_t)(uint8_t)
)来实现除最低字节以外的字节被重置。为此,按位和(0xFF &
)。强制转换的用法混淆了意图。
这个问题比仅使用凋零的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
这些都将整数值转换为双精度。但是,使用指针时,事情变得更加复杂。一些例子:
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。
他们只是使代码更加明确,使您看起来好像知道自己在做什么。
static_cast
表示您不能偶然const_cast
或reinterpret_cast
,这是一件好事。
请参阅有效的C ++简介
这是关于您要强加多少类型安全性。
当你写(bar) foo
(相当于reinterpret_cast<bar> foo
没有提供类型转换运算符),您是在告诉编译器忽略类型安全性,并按照提示执行操作。
在编写时,static_cast<bar> foo
您要求编译器至少检查类型转换是否有意义,对于整数类型,请插入一些转换代码。
编辑2014-02-26
我在5年前就写了这个答案,但我弄错了。(请参阅评论。)但是它仍然会被投票!
static_cast<bar>(foo)
,并带有括号。相同reinterpret_cast<bar>(foo)
。
除了处理指向类的指针之外,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
。更好的IMO。就是说,当我只需要一个表达式中的临时变量时,我会使用static_cast
并且从未使用过构造函数强制类型转换,我不认为。我只(C)casts
在急着编写debug cout
s 时使用...