什么是正确的用途:
static_cast
dynamic_cast
const_cast
reinterpret_cast
(type)value
(C 风格转换)type(value)
(函数式转换)
如何决定在哪些特定情况下使用哪个?
原文由 e.James 发布,翻译遵循 CC BY-SA 4.0 许可协议
什么是正确的用途:
static_cast
dynamic_cast
const_cast
reinterpret_cast
(type)value
(C 风格转换)type(value)
(函数式转换)如何决定在哪些特定情况下使用哪个?
原文由 e.James 发布,翻译遵循 CC BY-SA 4.0 许可协议
让我们看看 reinterpret_cast
和 static_cast
的区别:
#include <iostream>
using namespace std;
class A
{
int a;
};
class B
{
int b;
};
class C : public A, public B
{
int c;
};
int main()
{
{
B b;
cout << &b << endl;
cout << static_cast<C *>(&b) << endl; // 1
cout << reinterpret_cast<C *>(&b) << endl; // 2
}
cout << endl;
{
C c;
cout << &c << endl;
cout << static_cast<B *>(&c) << endl; // 3
cout << reinterpret_cast<B *>(&c) << endl; // 4
}
cout << endl;
{
A a;
cout << &a << endl;
cout << static_cast<C *>(&a) << endl;
cout << reinterpret_cast<C *>(&a) << endl;
}
cout << endl;
{
C c;
cout << &c << endl;
cout << static_cast<A *>(&c) << endl;
cout << reinterpret_cast<A *>(&c) << endl;
}
return 0;
}
产生输出:
0x7ffcede34f0c
0x7ffcede34f08 // 1
0x7ffcede34f0c // 2
0x7ffcede34f0c
0x7ffcede34f10 // 3
0x7ffcede34f0c // 4
0x7ffcede34f0c
0x7ffcede34f0c
0x7ffcede34f0c
0x7ffcede34f0c
0x7ffcede34f0c
0x7ffcede34f0c
注意输出 1
和 2
是不同的,以及 3
和 4
。这是为什么?其中一个是 static_cast
而另一个是 reinterpret_cast
在这两种情况下都是相同类型的相同输入。
情况可以用下图形象化:
C
包含一个 B
但 --- 的起始地址与 B
C
static_cast
正确计算 B
在 C
—内的地址。但是 reinterpret_cast
返回我们作为输入提供的相同地址,这对于这种情况是不正确的:在该地址没有 B
。
但是,当在 A
和 C
指针之间进行转换时,两种转换都返回相同的结果,因为它们恰好从相同的位置开始,顺便说一句,标准并不能保证。
原文由 Özgür Murat Sağdıçoğlu 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
static_cast
是您应该尝试使用的第一个演员表。它执行诸如类型之间的隐式转换(例如int
到float
或指向void*
的指针)之类的事情,并且它还可以调用显式函数转换(或隐式转换)那些)。在许多情况下,不需要明确声明static_cast
,但重要的是要注意T(something)
语法等同于(T)something
并且应该避免后来)。然而,T(something, something_else)
是安全的,并保证调用构造函数。static_cast
也可以通过继承层次结构进行转换。向上投射(朝向基类)时没有必要,但向下投射时,只要不通过virtual
继承就可以使用。但是,它不进行检查,并且static_cast
将层次结构向下到实际上不是对象类型的类型是未定义的行为。const_cast
可用于删除或添加const
到变量;没有其他 C++ 演员能够删除它(甚至reinterpret_cast
)。需要注意的是,只有当原始变量为const
时,修改以前的const
值才是未定义的;如果你用它来const
对没有用const
声明的东西的引用,它是安全的。例如,当基于const
重载成员函数时,这可能很有用。也可以用来给对象添加const
,比如调用成员函数重载。const_cast
也适用于volatile
,尽管这种情况不太常见。dynamic_cast
专门用于处理多态性。您可以将指向任何多态类型的指针或引用强制转换为任何其他类类型(多态类型至少有一个声明或继承的虚函数)。您不仅可以将其用于向下投射 - 您还可以向侧面投射,甚至可以向上投射另一条链。dynamic_cast
将寻找所需的对象并在可能的情况下返回它。如果不能,它将返回nullptr
在指针的情况下,或抛出std::bad_cast
在引用的情况下。dynamic_cast
但是有一些限制。如果继承层次结构中有多个相同类型的对象(所谓的“可怕的菱形”)并且您没有使用virtual
继承,则它不起作用。它也只能通过公共继承 - 它总是无法通过protected
或private
继承。然而,这很少成为问题,因为这种继承形式很少见。reinterpret_cast
是最危险的演员,应该非常谨慎地使用。它将一种类型直接转换为另一种类型——例如将值从一个指针转换为另一种,或将指针存储在int
或各种其他讨厌的事情中。很大程度上,您使用reinterpret_cast
获得的唯一保证是,通常如果您将结果转换回原始类型,您将获得完全相同的值(但如果中间类型小于原始类型,则 不会) .有许多转换是reinterpret_cast
也不能做的。它主要用于特别奇怪的转换和位操作,例如将原始数据流转换为实际数据,或将数据存储在指向对齐数据的指针的低位中。C 风格 转换和 函数风格 转换分别使用
(type)object
或type(object)
进行转换,并且在功能上是等效的。它们被定义为以下成功的第一个:const_cast
static_cast
(尽管忽略访问限制)static_cast
(见上文),然后const_cast
reinterpret_cast
reinterpret_cast
,然后const_cast
因此,在某些情况下,它可以用作其他演员表的替代品,但由于能够演变为
reinterpret_cast
,因此可能非常危险,并且在需要显式转换时应首选后者,除非您确定static_cast
会成功或reinterpret_cast
会失败。即便如此,考虑更长、更明确的选项。在执行
static_cast
时,C 样式转换也会忽略访问控制,这意味着它们能够执行其他转换无法执行的操作。不过,这主要是一个杂物,在我看来,这只是避免 C 风格转换的另一个原因。