C++ 常规转换 vs. static_cast vs. dynamic_cast

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28002/
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 12:20:07  来源:igfitidea点击:

Regular cast vs. static_cast vs. dynamic_cast

c++pointerscasting

提问by Graeme Perrow

I've been writing C and C++ code for almost twenty years, but there's one aspect of these languages that I've never really understood. I've obviously used regular casts i.e.

我已经编写 C 和 C++ 代码将近 20 年了,但是我从未真正理解这些语言的一个方面。我显然使用过常规演员表,即

MyClass *m = (MyClass *)ptr;

all over the place, but there seem to be two other types of casts, and I don't know the difference. What's the difference between the following lines of code?

到处都是,但似乎还有另外两种类型的演员阵容,我不知道有什么区别。以下代码行之间有什么区别?

MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);

采纳答案by Johannes Schaub - litb

static_cast

static_cast

static_castis used for cases where you basically want to reverse an implicit conversion, with a few restrictions and additions. static_castperforms no runtime checks. This should be used if you know that you refer to an object of a specific type, and thus a check would be unnecessary. Example:

static_cast用于您基本上想要反转隐式转换的情况,但有一些限制和添加。static_cast不执行运行时检查。如果您知道您引用了特定类型的对象,则应该使用它,因此无需检查。例子:

void func(void *data) {
  // Conversion from MyClass* -> void* is implicit
  MyClass *c = static_cast<MyClass*>(data);
  ...
}

int main() {
  MyClass c;
  start_thread(&func, &c)  // func(&c) will be called
      .join();
}

In this example, you know that you passed a MyClassobject, and thus there isn't any need for a runtime check to ensure this.

在这个例子中,你知道你传递了一个MyClass对象,因此不需要运行时检查来确保这一点。

dynamic_cast

dynamic_cast

dynamic_castis useful when you don't know what the dynamic type of the object is. It returns a null pointer if the object referred to doesn't contain the type casted to as a base class (when you cast to a reference, a bad_castexception is thrown in that case).

dynamic_cast当您不知道对象的动态类型是什么时很有用。如果引用的对象不包含转换为基类的类型(当您转换为引用时,bad_cast在这种情况下会抛出异常),它返回一个空指针。

if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
  ...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
  ...
}

You cannot use dynamic_castif you downcast (cast to a derived class) and the argument type is not polymorphic. For example, the following code is not valid, because Basedoesn't contain any virtual function:

不能使用dynamic_cast,如果你垂头丧气(投派生类)和参数类型不是多态。例如,以下代码无效,因为Base不包含任何虚函数:

struct Base { };
struct Derived : Base { };
int main() {
  Derived d; Base *b = &d;
  dynamic_cast<Derived*>(b); // Invalid
}

An "up-cast" (cast to the base class) is always valid with both static_castand dynamic_cast, and also without any cast, as an "up-cast" is an implicit conversion.

“向上转换”(转换到基类)始终对static_cast和有效dynamic_cast,并且没有任何转换,因为“向上转换”是隐式转换。

Regular Cast

普通演员

These casts are also called C-style cast. A C-style cast is basically identical to trying out a range of sequences of C++ casts, and taking the first C++ cast that works, without ever considering dynamic_cast. Needless to say, this is much more powerful as it combines all of const_cast, static_castand reinterpret_cast, but it's also unsafe, because it does not use dynamic_cast.

这些类型转换也称为 C 风格类型转换。C 风格的强制转换基本上等同于尝试一系列 C++ 强制转换,并采用第一个有效的 C++ 强制转换,而从不考虑dynamic_cast. 不用说,这更强大,因为它结合了所有const_cast, static_castand reinterpret_cast,但它也不安全,因为它不使用dynamic_cast.

In addition, C-style casts not only allow you to do this, but they also allow you to safely cast to a private base-class, while the "equivalent" static_castsequence would give you a compile-time error for that.

此外,C 样式的强制转换不仅允许您执行此操作,而且还允许您安全地强制转换为私有基类,而“等效”static_cast序列会为此产生编译时错误。

Some people prefer C-style casts because of their brevity. I use them for numeric casts only, and use the appropriate C++ casts when user defined types are involved, as they provide stricter checking.

有些人更喜欢 C 风格的类型转换,因为它们很简洁。我仅将它们用于数字转换,并在涉及用户定义类型时使用适当的 C++ 转换,因为它们提供更严格的检查。

回答by Rika

Static cast

静态转换

The static cast performs conversions between compatible types. It is similar to the C-style cast, but is more restrictive. For example, the C-style cast would allow an integer pointer to point to a char.

静态类型转换执行兼容类型之间的转换。它类似于 C 风格的强制转换,但限制性更强。例如,C 风格的强制转换将允许一个整数指针指向一个字符。

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

Since this results in a 4-byte pointer pointing to 1 byte of allocated memory, writing to this pointer will either cause a run-time error or will overwrite some adjacent memory.

由于这会导致 4 字节的指针指向 1 字节的已分配内存,因此写入此指针将导致运行时错误或覆盖某些相邻内存。

*p = 5; // run-time error: stack corruption

In contrast to the C-style cast, the static cast will allow the compiler to check that the pointer and pointee data types are compatible, which allows the programmer to catch this incorrect pointer assignment during compilation.

与 C 风格的转换不同,静态转换将允许编译器检查指针和被指点数据类型是否兼容,这允许程序员在编译期间捕获这种不正确的指针分配。

int *q = static_cast<int*>(&c); // compile-time error

Reinterpret cast

重新诠释演员表

To force the pointer conversion, in the same way as the C-style cast does in the background, the reinterpret cast would be used instead.

为了强制指针转换,与在后台执行 C 样式转换的方式相同,将改用重新解释转换。

int *r = reinterpret_cast<int*>(&c); // forced conversion

This cast handles conversions between certain unrelated types, such as from one pointer type to another incompatible pointer type. It will simply perform a binary copy of the data without altering the underlying bit pattern. Note that the result of such a low-level operation is system-specific and therefore not portable. It should be used with caution if it cannot be avoided altogether.

此强制转换处理某些不相关类型之间的转换,例如从一种指针类型到另一种不兼容的指针类型。它将简单地执行数据的二进制副本,而不会改变底层位模式。请注意,这种低级操作的结果是特定于系统的,因此不可移植。如果不能完全避免,则应谨慎使用。

Dynamic cast

动态演员表

This one is only used to convert object pointers and object references into other pointer or reference types in the inheritance hierarchy. It is the only cast that makes sure that the object pointed to can be converted, by performing a run-time check that the pointer refers to a complete object of the destination type. For this run-time check to be possible the object must be polymorphic. That is, the class must define or inherit at least one virtual function. This is because the compiler will only generate the needed run-time type information for such objects.

这个仅用于将对象指针和对象引用转换为继承层次结构中的其他指针或引用类型。它是唯一一种通过执行运行时检查指针是否指向目标类型的完整对象来确保所指向的对象可以转换的强制转换。为了使这个运行时检查成为可能,对象必须是多态的。也就是说,该类必须定义或继承至少一个虚函数。这是因为编译器只会为这些对象生成所需的运行时类型信息。

Dynamic cast examples

动态转换示例

In the example below, a MyChild pointer is converted into a MyBase pointer using a dynamic cast. This derived-to-base conversion succeeds, because the Child object includes a complete Base object.

在下面的示例中,使用动态强制转换将 MyChild 指针转换为 MyBase 指针。这种从派生到基的转换成功,因为 Child 对象包括一个完整的 Base 对象。

class MyBase 
{ 
  public:
  virtual void test() {}
};
class MyChild : public MyBase {};



int main()
{
  MyChild *child = new MyChild();
  MyBase  *base = dynamic_cast<MyBase*>(child); // ok
}

The next example attempts to convert a MyBase pointer to a MyChild pointer. Since the Base object does not contain a complete Child object this pointer conversion will fail. To indicate this, the dynamic cast returns a null pointer. This gives a convenient way to check whether or not a conversion has succeeded during run-time.

下一个示例尝试将 MyBase 指针转换为 MyChild 指针。由于 Base 对象不包含完整的 Child 对象,因此此指针转换将失败。为了表明这一点,动态转换返回一个空指针。这提供了一种在运行时检查转换是否成功的便捷方法。

MyBase  *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);


if (child == 0) 
std::cout << "Null pointer returned";

If a reference is converted instead of a pointer, the dynamic cast will then fail by throwing a bad_cast exception. This needs to be handled using a try-catch statement.

如果转换的是引用而不是指针,则动态转换将因抛出 bad_cast 异常而失败。这需要使用 try-catch 语句来处理。

#include <exception>
// …  
try
{ 
  MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e) 
{ 
  std::cout << e.what(); // bad dynamic_cast
}

Dynamic or static cast

动态或静态转换

The advantage of using a dynamic cast is that it allows the programmer to check whether or not a conversion has succeeded during run-time. The disadvantage is that there is a performance overhead associated with doing this check. For this reason using a static cast would have been preferable in the first example, because a derived-to-base conversion will never fail.

使用动态转换的优点是它允许程序员在运行时检查转换是否成功。缺点是执行此检查会产生性能开销。出于这个原因,在第一个示例中使用静态转换会更可取,因为派生到基类的转换永远不会失败。

MyBase *base = static_cast<MyBase*>(child); // ok

However, in the second example the conversion may either succeed or fail. It will fail if the MyBase object contains a MyBase instance and it will succeed if it contains a MyChild instance. In some situations this may not be known until run-time. When this is the case dynamic cast is a better choice than static cast.

但是,在第二个示例中,转换可能成功也可能失败。如果 MyBase 对象包含 MyBase 实例,它将失败,如果它包含 MyChild 实例,它将成功。在某些情况下,这可能直到运行时才知道。在这种情况下,动态转换是比静态转换更好的选择。

// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);

If the base-to-derived conversion had been performed using a static cast instead of a dynamic cast the conversion would not have failed. It would have returned a pointer that referred to an incomplete object. Dereferencing such a pointer can lead to run-time errors.

如果使用静态强制转换而不是动态强制转换来执行从基到派生的转换,则转换不会失败。它会返回一个指向不完整对象的指针。取消引用这样的指针会导致运行时错误。

// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);

// Incomplete MyChild object dereferenced
(*child);

Const cast

常量演员表

This one is primarily used to add or remove the const modifier of a variable.

这主要用于添加或删除变量的 const 修饰符。

const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const

Although const cast allows the value of a constant to be changed, doing so is still invalid code that may cause a run-time error. This could occur for example if the constant was located in a section of read-only memory.

尽管 const cast 允许更改常量的值,但这样做仍然是可能导致运行时错误的无效代码。例如,如果常量位于只读存储器的一部分中,就会发生这种情况。

*nonConst = 10; // potential run-time error

Const cast is instead used mainly when there is a function that takes a non-constant pointer argument, even though it does not modify the pointee.

Const cast 主要用于当有一个函数采用非常量指针参数时,即使它不修改指针对象。

void print(int *p) 
{
   std::cout << *p;
}

The function can then be passed a constant variable by using a const cast.

然后可以通过使用 const 强制转换向该函数传递一个常量变量。

print(&myConst); // error: cannot convert 
                 // const int* to int*

print(nonConst); // allowed

Source and More Explanations

来源和更多解释

回答by TJ Seabrooks

You should look at the article C++ Programming/Type Casting.

您应该查看C++ Programming/Type Casting 一文

It contains a good description of all of the different cast types. The following taken from the above link:

它包含对所有不同类型转换的很好的描述。以下摘自上述链接:

const_cast

const_cast(expression) The const_cast<>() is used to add/remove const(ness) (or volatile-ness) of a variable.

static_cast

static_cast(expression) The static_cast<>() is used to cast between the integer types. 'e.g.' char->long, int->short etc.

Static cast is also used to cast pointers to related types, for example casting void* to the appropriate type.

dynamic_cast

Dynamic cast is used to convert pointers and references at run-time, generally for the purpose of casting a pointer or reference up or down an inheritance chain (inheritance hierarchy).

dynamic_cast(expression)

The target type must be a pointer or reference type, and the expression must evaluate to a pointer or reference. Dynamic cast works only when the type of object to which the expression refers is compatible with the target type and the base class has at least one virtual member function. If not, and the type of expression being cast is a pointer, NULL is returned, if a dynamic cast on a reference fails, a bad_cast exception is thrown. When it doesn't fail, dynamic cast returns a pointer or reference of the target type to the object to which expression referred.

reinterpret_cast

Reinterpret cast simply casts one type bitwise to another. Any pointer or integral type can be casted to any other with reinterpret cast, easily allowing for misuse. For instance, with reinterpret cast one might, unsafely, cast an integer pointer to a string pointer.

const_cast

const_cast(expression) const_cast<>() 用于添加/删除变量的 const(ness)(或 volatile-ness)。

static_cast

static_cast(expression) static_cast<>() 用于在整数类型之间进行转换。'eg' char->long, int->short 等。

静态转换还用于将指针转换为相关类型,例如将 void* 转换为适当的类型。

dynamic_cast

动态转换用于在运行时转换指针和引用,通常用于在继承链(继承层次结构)上或下转换指针或引用。

dynamic_cast(表达式)

目标类型必须是指针或引用类型,表达式的计算结果必须是指针或引用。只有当表达式所引用的对象类型与目标类型兼容并且基类至少具有一个虚拟成员函数时,动态转换才起作用。如果不是,并且正在转换的表达式类型是指针,则返回 NULL,如果对引用的动态转换失败,则会抛出 bad_cast 异常。当它没有失败时,动态转换将目标类型的指针或引用返回到表达式所引用的对象。

reinterpret_cast

Reinterpret cast 只是将一种类型按位转换为另一种类型。任何指针或整数类型都可以通过重新解释转换转换为任何其他类型,很容易被误用。例如,使用 reinterpret cast 可能会不安全地将整数指针转换为字符串指针。

回答by Jason Baker

FYI, I believe Bjarne Stroustrup is quoted as saying that C-style casts are to be avoided and that you should use static_cast or dynamic_cast if at all possible.

仅供参考,我相信引用 Bjarne Stroustrup 的话说应该避免 C 风格的强制转换,如果可能的话,你应该使用 static_cast 或 dynamic_cast。

Barne Stroustrup's C++ style FAQ

Barne Stroustrup 的 C++ 风格常见问题解答

Take that advice for what you will. I'm far from being a C++ guru.

根据您的意愿接受该建议。我远非 C++ 大师。

回答by ugasoft

Avoid using C-Style casts.

避免使用 C 风格的强制转换。

C-style casts are a mix of const and reinterpret cast, and it's difficult to find-and-replace in your code. A C++ application programmer should avoid C-style cast.

C 风格的转换是 const 和重新解释转换的混合体,很难在代码中找到和替换。C++ 应用程序程序员应该避免 C 风格的强制转换。

回答by DrPizza

C-style casts conflate const_cast, static_cast, and reinterpret_cast.

C 风格的强制转换将 const_cast、static_cast 和 reinterpret_cast 混为一谈。

I wish C++ didn't have C-style casts. C++ casts stand out properly (as they should; casts are normally indicative of doing something bad) and properly distinguish between the different kinds of conversion that casts perform. They also permit similar-looking functions to be written, e.g. boost::lexical_cast, which is quite nice from a consistency perspective.

我希望 C++ 没有 C 风格的强制转换。C++ 强制转换正确地脱颖而出(正如它们应该的那样;强制转换通常表示做坏事)并正确区分强制转换执行的不同类型的转换。它们还允许编写外观相似的函数,例如 boost::lexical_cast,从一致性的角度来看,这是非常好的。

回答by larsmoa

dynamic_castonly supports pointer and reference types. It returns NULLif the cast is impossible if the type is a pointer or throws an exception if the type is a reference type. Hence, dynamic_castcan be used to check if an object is of a given type, static_castcannot (you will simply end up with an invalid value).

dynamic_cast只支持指针和引用类型。NULL如果类型是指针,则在无法进行强制转换时返回,如果类型是引用类型则抛出异常。因此,dynamic_cast可用于检查对象是否属于给定类型,static_cast不能(您最终会得到无效值)。

C-style (and other) casts have been covered in the other answers.

其他答案中已涵盖 C 风格(和其他)类型转换。

回答by Inisheer

dynamic_casthas runtime type checking and only works with references and pointers, whereas static_castdoes not offer runtime type checking. For complete information, see the MSDN article static_cast Operator.

dynamic_cast具有运行时类型检查,仅适用于引用和指针,static_cast而不提供运行时类型检查。有关完整信息,请参阅 MSDN 文章static_cast Operator