C++ 什么时候应该使用 static_cast、dynamic_cast、const_cast 和 reinterpret_cast?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/332030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:42:01  来源:igfitidea点击:

When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?

c++pointerscastingc++-faq

提问by e.James

What are the proper uses of:

什么是正确的用法:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C-style cast (type)value
  • Function-style cast type(value)
  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C 风格演员表 (type)value
  • 函数式类型转换 type(value)

How does one decide which to use in which specific cases?

如何决定在哪些特定情况下使用哪个?

回答by coppro

static_castis the first cast you should attempt to use. It does things like implicit conversions between types (such as intto float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_castisn't necessary, but it's important to note that the T(something)syntax is equivalent to (T)somethingand should be avoided (more on that later). A T(something, something_else)is safe, however, and guaranteed to call the constructor.

static_cast是您应该尝试使用的第一个演员表。它执行类型之间的隐式转换(例如inttofloat或指针 to void*),它还可以调用显式转换函数(或隐式转换函数)。在许多情况下,static_cast没有必要明确说明,但重要的是要注意T(something)语法等效于(T)something并且应该避免(稍后会详细介绍)。T(something, something_else)然而,A是安全的,并且保证调用构造函数。

static_castcan also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtualinheritance. It does not do checking, however, and it is undefined behavior to static_castdown a hierarchy to a type that isn't actually the type of the object.

static_cast也可以通过继承层次结构进行转换。向上转换(朝向基类)时没有必要,但是向下转换时,只要不通过virtual继承转换就可以使用。但是,它不进行检查,并且将static_cast层次结构向下传递到实际上不是对象类型的类型是未定义的行为。



const_castcan be used to remove or add constto a variable; no other C++ cast is capable of removing it (not even reinterpret_cast). It is important to note that modifying a formerly constvalue is only undefined if the original variable is const; if you use it to take the constoff a reference to something that wasn't declared with const, it is safe. This can be useful when overloading member functions based on const, for instance. It can also be used to add constto an object, such as to call a member function overload.

const_cast可用于删除或添加const变量;没有其他 C++ 演员能够删除它(甚至没有reinterpret_cast)。重要的是要注意,const只有在原始变量是const;如果您使用它来取消对const未用 声明的内容的引用const,则它是安全的。例如,这在基于 重载成员函数时很有用const。它还可以用于添加const到对象,例如调用成员函数重载。

const_castalso works similarly on volatile, though that's less common.

const_cast在 上也有类似的作用volatile,尽管这种情况不太常见。



dynamic_castis exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards – you can cast sideways or even up another chain. The dynamic_castwill seek out the desired object and return it if possible. If it can't, it will return nullptrin the case of a pointer, or throw std::bad_castin the case of a reference.

dynamic_cast专门用于处理多态性。您可以将指向任何多态类型的指针或引用转换为任何其他类类型(多态类型至少具有一个声明或继承的虚函数)。您不仅可以将其用于向下抛掷 – 您还可以向侧面抛掷甚至向上抛掷另一条链。该dynamic_cast会寻求所需的对象,如果可能的话返回。如果不能,它会nullptr在指针的情况下返回,或者std::bad_cast在引用的情况下抛出。

dynamic_casthas some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtualinheritance. It also can only go through public inheritance - it will always fail to travel through protectedor privateinheritance. This is rarely an issue, however, as such forms of inheritance are rare.

dynamic_cast但是有一些限制。如果继承层次结构中有多个相同类型的对象(所谓的“可怕的菱形”)并且您没有使用virtual继承,则它不起作用。它也只能通过公共继承——它总是无法通过protectedprivate继承。然而,这很少成为问题,因为这种形式的继承很少见。



reinterpret_castis the most dangerous cast, and should be used very sparingly. It turns one type directly into another — such as casting the value from one pointer to another, or storing a pointer in an int, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_castis that normally if you cast the result back to the original type, you will get the exact same value (but notif the intermediate type is smaller than the original type). There are a number of conversions that reinterpret_castcannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of a pointer to aligned data.

reinterpret_cast是最危险的演员,应该非常谨慎地使用。它将一种类型直接转换为另一种类型——例如将值从一个指针转换为另一种,或者将指针存储在 an 中int,或者其他各种令人讨厌的东西。在很大程度上,您得到的唯一保证reinterpret_cast是,通常如果您将结果转换回原始类型,您将获得完全相同的值(但如果中间类型小于原始类型,则不会)。也有许多转换reinterpret_cast无法完成。它主要用于特别奇怪的转换和位操作,例如将原始数据流转换为实际数据,或将数据存储在指向对齐数据的指针的低位中。



C-style castand function-style castare casts using (type)objector type(object), respectively, and are functionally equivalent. They are defined as the first of the following which succeeds:

C 样式转换和函数样式转换分别是使用(type)object或 的转换type(object),并且在功能上是等效的。它们被定义为以下第一个成功的:

  • const_cast
  • static_cast(though ignoring access restrictions)
  • static_cast(see above), then const_cast
  • reinterpret_cast
  • reinterpret_cast, then const_cast
  • const_cast
  • static_cast(虽然忽略访问限制)
  • static_cast(见上文),然后 const_cast
  • reinterpret_cast
  • reinterpret_cast, 然后 const_cast

It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast, and the latter should be preferred when explicit casting is needed, unless you are sure static_castwill succeed or reinterpret_castwill fail. Even then, consider the longer, more explicit option.

因此,在某些情况下,它可以用作其他强制转换的替代品,但由于能够转化为 a reinterpret_cast,因此可能非常危险,并且在需要显式强制转换时应首选后者,除非您确定static_cast会成功或reinterpret_cast会失败. 即便如此,请考虑更长、更明确的选项。

C-style casts also ignore access control when performing a static_cast, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.

C 样式强制转换在执行 a 时也会忽略访问控制static_cast,这意味着它们能够执行其他强制转换无法执行的操作。不过,这主要是杂乱无章,在我看来,这只是避免 C 风格强制转换的另一个原因。

回答by Fred Larson

Use dynamic_castfor converting pointers/references within an inheritance hierarchy.

使用dynamic_cast一个继承层次内进行转化的指针/引用。

Use static_castfor ordinary type conversions.

使用static_cast普通类型转换。

Use reinterpret_castfor low-level reinterpreting of bit patterns. Use with extreme caution.

使用reinterpret_cast低层次的重新解释的位模式。谨慎使用。

Use const_castfor casting away const/volatile. Avoid this unless you are stuck using a const-incorrect API.

使用const_cast铸造远const/volatile。避免这种情况,除非您使用 const 不正确的 API。

回答by Sumit Arora

(A lot of theoretical and conceptual explanation has been given above)

(上面已经给出了很多理论和概念上的解释)

Below are some of the practical exampleswhen I used static_cast, dynamic_cast, const_cast, reinterpret_cast.

以下是我使用static_castdynamic_castconst_castreinterpret_cast时的一些实际示例

(Also referes this to understand the explaination : http://www.cplusplus.com/doc/tutorial/typecasting/)

(也参考这个来理解解释:http: //www.cplusplus.com/doc/tutorial/typecasting/

static_cast :

静态铸造:

OnEventData(void* pData)

{
  ......

  //  pData is a void* pData, 

  //  EventData is a structure e.g. 
  //  typedef struct _EventData {
  //  std::string id;
  //  std:: string remote_id;
  //  } EventData;

  // On Some Situation a void pointer *pData
  // has been static_casted as 
  // EventData* pointer 

  EventData *evtdata = static_cast<EventData*>(pData);
  .....
}

dynamic_cast :

动态铸造:

void DebugLog::OnMessage(Message *msg)
{
    static DebugMsgData *debug;
    static XYZMsgData *xyz;

    if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){
        // debug message
    }
    else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){
        // xyz message
    }
    else/* if( ... )*/{
        // ...
    }
}

const_cast :

const_cast :

// *Passwd declared as a const

const unsigned char *Passwd


// on some situation it require to remove its constness

const_cast<unsigned char*>(Passwd)

reinterpret_cast :

reinterpret_cast :

typedef unsigned short uint16;

// Read Bytes returns that 2 bytes got read. 

bool ByteBuffer::ReadUInt16(uint16& val) {
  return ReadBytes(reinterpret_cast<char*>(&val), 2);
}

回答by Shital Shah

It might help if you know little bit of internals...

如果您了解一点内部知识,它可能会有所帮助......

static_cast

static_cast

  • C++ compiler already knows how to convert between scaler types such as float to int. Use static_castfor them.
  • When you ask compiler to convert from type Ato B, static_castcalls B's constructor passing Aas param. Alternatively, Acould have a conversion operator (i.e. A::operator B()). If Bdoesn't have such constructor, or Adoesn't have a conversion operator, then you get compile time error.
  • Cast from A*to B*always succeeds if A and B are in inheritance hierarchy (or void) otherwise you get compile error.
  • Gotcha: If you cast base pointer to derived pointer but if actual object is not really derived type then you don'tget error. You get bad pointer and very likely a segfault at runtime. Same goes for A&to B&.
  • Gotcha: Cast from Derived to Base or viceversa creates newcopy! For people coming from C#/Java, this can be a huge surprise because the result is basically a chopped off object created from Derived.
  • C++ 编译器已经知道如何在诸如 float 和 int 之类的缩放器类型之间进行转换。static_cast为他们使用。
  • 当您要求编译器从类型转换A为 时Bstatic_cast调用作为参数B传递的构造函数A。或者,A可以有一个转换运算符(即A::operator B())。如果B没有这样的构造函数,或者A没有转换运算符,则会出现编译时错误。
  • 如果 A 和 B 处于继承层次结构(或无效)中,则从A*to 转换B*总是成功,否则会出现编译错误。
  • 问题:如果您将基指针转换为派生指针,但如果实际对象不是真正的派生类型,则不会出错。你得到错误的指针,很可能在运行时出现段错误。这同样适用于A&B&
  • 问题:从派生转换到基础,反之亦然创建副本!对于来自 C#/Java 的人来说,这可能是一个巨大的惊喜,因为结果基本上是从 Derived 创建的一个切碎的对象。

dynamic_cast

dynamic_cast

  • dynamic_cast uses runtime type information to figure out if cast is valid. For example, (Base*)to (Derived*)may fail if pointer is not actually of derived type.
  • This means, dynamic_cast is very expensive compared to static_cast!
  • For A*to B*, if cast is invalid then dynamic_cast will return nullptr.
  • For A&to B&if cast is invalid then dynamic_cast will throw bad_cast exception.
  • Unlike other casts, there is runtime overhead.
  • dynamic_cast 使用运行时类型信息来确定强制转换是否有效。例如,如果指针实际上不是派生类型,则(Base*)to(Derived*)可能会失败。
  • 这意味着,与 static_cast 相比,dynamic_cast 非常昂贵!
  • 对于A*to B*,如果 cast 无效,则 dynamic_cast 将返回 nullptr。
  • 对于A&toB&如果 cast 无效,则 dynamic_cast 将抛出 bad_cast 异常。
  • 与其他类型转换不同,有运行时开销。

const_cast

const_cast

  • While static_cast can do non-const to const it can't go other way around. The const_cast can do both ways.
  • One example where this comes handy is iterating through some container like set<T>which only returns its elements as const to make sure you don't change its key. However if your intent is to modify object's non-key members then it should be ok. You can use const_cast to remove constness.
  • Another example is when you want to implement T& SomeClass::foo()as well as const T& SomeClass::foo() const. To avoid code duplication, you can apply const_cast to return value of one function from another.
  • 虽然 static_cast 可以对 const 执行非常量,但不能反过来。const_cast 可以做两种方式。
  • 一个很方便的示例是遍历某个容器,例如set<T>只将其元素作为 const 返回以确保您不会更改其键。但是,如果您的意图是修改对象的非关键成员,那么应该没问题。您可以使用 const_cast 来删除常量。
  • 另一个例子是当你想要实现T& SomeClass::foo()以及const T& SomeClass::foo() const. 为避免代码重复,您可以应用 const_cast 从另一个函数返回一个函数的值。

reinterpret_cast

reinterpret_cast

  • This basically says that take these bytes at this memory location and think of it as given object.
  • For example, you can load 4 bytes of float to 4 bytes of int to see how bits in float looks like.
  • Obviously, if data is not correct for the type, you may get segfault.
  • There is no runtime overhead for this cast.
  • 这基本上是说在这个内存位置获取这些字节并将其视为给定的对象。
  • 例如,您可以将 4 个字节的 float 加载到 4 个字节的 int 以查看 float 中的位是什么样的。
  • 显然,如果数据类型不正确,您可能会遇到段错误。
  • 此演员表没有运行时开销。

回答by andreas buykx

Does thisanswer your question?

是否回答了您的问题?

I have never used reinterpret_cast, and wonder whether running into a case that needs it isn't a smell of bad design. In the code base I work on dynamic_castis used a lot. The difference with static_castis that a dynamic_castdoes runtime checking which may (safer) or may not (more overhead) be what you want (see msdn).

我从未使用过reinterpret_cast,并且想知道遇到需要它的情况是否不是设计不好的味道。在我工作的代码库dynamic_cast中使用了很多。不同之 static_cast处在于 a 进行dynamic_cast运行时检查,这可能(更安全)或可能不是(更多开销)是您想要的(请参阅msdn)。

回答by Serge Rogatch

In addition to the other answers so far, here is unobvious example where static_castis not sufficient so that reinterpret_castis needed. Suppose there is a function which in an output parameter returns pointers to objects of different classes (which do not share a common base class). A real example of such function is CoCreateInstance()(see the last parameter, which is in fact void**). Suppose you request particular class of object from this function, so you know in advance the type for the pointer (which you often do for COM objects). In this case you cannot cast pointer to your pointer into void**with static_cast: you need reinterpret_cast<void**>(&yourPointer).

除了到目前为止的其他答案之外,这里还有一个不明显的例子,其中static_cast不够充分,因此reinterpret_cast需要。假设有一个函数在输出参数中返回指向不同类(不共享公共基类)的对象的指针。此类函数的一个真实示例是CoCreateInstance()(请参阅最后一个参数,实际上是void**)。假设您从该函数请求特定类的对象,因此您事先知道指针的类型(您经常为 COM 对象这样做)。在这种情况下,您不能将指向您的指针的指针转换为void**with static_cast:您需要reinterpret_cast<void**>(&yourPointer)

In code:

在代码中:

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    //static_cast<void**>(&pNetFwPolicy2) would give a compile error
    reinterpret_cast<void**>(&pNetFwPolicy2) );

However, static_castworks for simple pointers (not pointers to pointers), so the above code can be rewritten to avoid reinterpret_cast(at a price of an extra variable) in the following way:

但是,它static_cast适用于简单的指针(不是指向指针的指针),因此可以通过reinterpret_cast以下方式重写上述代码以避免(以额外变量为代价):

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
void* tmp = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    &tmp );
pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);

回答by Timmy_A

While other answers nicely described all differences between C++ casts, I would like to add a short note why you should not use C-style casts (Type) varand Type(var).

虽然其他答案很好地描述了 C++ 类型转换之间的所有差异,但我想添加一个简短说明,为什么您不应该使用 C 样式类型转换(Type) varType(var).

For C++ beginners C-style casts look like being the superset operation over C++ casts (static_cast<>(), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()) and someone could prefer them over the C++ casts. In fact C-style cast is the superset and shorter to write.

对于 C++ 初学者来说,C 风格的强制转换看起来像是 C++ 强制转换的超集操作(static_cast<>()、dynamic_cast<>()、const_cast<>()、reinterpret_cast<>()),有人可能更喜欢它们而不是 C++ 强制转换. 事实上,C 风格的类型转换是超集,而且写起来更短。

The main problem of C-style casts is that they hide developer real intention of the cast. The C-style casts can do virtually all types of casting from normally safe casts done by static_cast<>() and dynamic_cast<>() to potentially dangerous casts like const_cast<>(), where const modifier can be removed so the const variables can be modified and reinterpret_cast<>() that can even reinterpret integer values to pointers.

C 风格强制转换的主要问题是它们隐藏了开发人员强制转换的真实意图。C 风格的转换几乎可以进行所有类型的转换,从通常由 static_cast<>() 和 dynamic_cast<>() 完成的安全转换到像 const_cast<>() 这样的潜在危险转换,其中可以删除 const 修饰符,以便 const 变量可以修改和 reinterpret_cast<>() 甚至可以将整数值重新解释为指针。

Here is the sample.

这是示例。

int a=rand(); // Random number.

int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation.

int* pa2=static_cast<int*>(a); // Compiler error.
int* pa3=dynamic_cast<int*>(a); // Compiler error.

int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo.

*pa4=5; // Program crashes.

The main reason why C++ casts were added to the language was to allow a developer to clarify his intentions - why he is going to do that cast. By using C-style casts which are perfectly valid in C++ you are making your code less readable and more error prone especially for other developers who didn't create your code. So to make your code more readable and explicit you should always prefer C++ casts over C-style casts.

将 C++ 类型转换添加到语言中的主要原因是为了让开发人员阐明他的意图 - 为什么他要进行这种转换。通过使用在 C++ 中完全有效的 C 样式强制转换,您会降低代码的可读性并且更容易出错,尤其是对于没有创建代码的其他开发人员。因此,为了使您的代码更具可读性和明确性,您应该始终更喜欢 C++ 类型转换而不是 C 风格转换。

Here is a short quote from Bjarne Stroustrup's (the author of C++) book The C++ Programming Language 4th edition - page 302.

这是 Bjarne Stroustrup(C++ 的作者)的书 The C++ Programming Language 4th edition - page 302 的简短引述。

This C-style cast is far more dangerous than the named conversion operators because the notation is harder to spot in a large program and the kind of conversion intended by the programmer is not explicit.

这种 C 风格的类型转换比命名转换运算符危险得多,因为这种表示法在大型程序中更难发现,而且程序员想要的转换类型并不明确。

回答by Pankaj Kumar Thapa

To understand, let's consider below code snippet:

为了理解,让我们考虑以下代码片段:

struct Foo{};
struct Bar{};

int main(int argc, char** argv)
{
    Foo* f = new Foo;

    Bar* b1 = f;                              // (1)
    Bar* b2 = static_cast<Bar*>(f);           // (2)
    Bar* b3 = dynamic_cast<Bar*>(f);          // (3)
    Bar* b4 = reinterpret_cast<Bar*>(f);      // (4)
    Bar* b5 = const_cast<Bar*>(f);            // (5)

    return 0;
}

Only line (4) compiles without error. Only reinterpret_castcan be used to convert a pointer to an object to a pointer to an any unrelated object type.

只有第 (4) 行编译没有错误。只有reinterpret_cast可用于将指向对象的指针转换为指向任何不相关对象类型的指针。

One this to be noted is: The dynamic_castwould fail at run-time, however on most compilers it will also fail to compile because there are no virtual functions in the struct of the pointer being casted, meaning dynamic_castwill work with only polymorphic class pointers.

需要注意的一点是:dynamic_cast会在运行时失败,但是在大多数编译器上它也将无法编译,因为被转换的指针结构中没有虚函数,这意味着dynamic_cast将仅适用于多态类指针.

When to use C++ cast:

何时使用 C++ 演员表

  • Use static_castas the equivalent of a C-style cast that does value conversion, or when we need to explicitly up-cast a pointer from a class to its superclass.
  • Use const_castto remove the const qualifier.
  • Use reinterpret_castto do unsafe conversions of pointer types to and from integer and other pointer types. Use this only if we know what we are doing and we understand the aliasing issues.
  • 使用static_cast作为进行值转换的 C 样式转换的等价物,或者当我们需要显式地将指针从类向上转换到其超类时。
  • 使用const_cast删除 const 限定符。
  • 使用reinterpret_cast进行指针类型与整数和其他指针类型之间的不安全转换。仅当我们知道我们在做什么并且我们了解别名问题时才使用它。