C++|类型转换适用的时机与场合

C++|类型转换适用的时机与场合When to use which cast in c++:Use dynamic_cast for converting pointers/r

大家好,欢迎来到IT知识分享网。

When to use which cast in c++:

Use dynamic_cast for converting pointers/references within an inheritance hierarchy.

Use static_cast for ordinary type conversions.

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

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

C++ also supports function-style cast notation, T(expr), and C-style cast notation, (T)expr.

C++还支持函数样式转换表示法T(expr)和C风格类型转换表示法(T)expr。

C-Style casting can be considered ‘Best effort’ casting and is named so as it is the only cast which could be used in C. The syntax for this cast is (NewType)variable.

C风格类型转换表示法可以被认为是“尽力而为”的casting,之所以这样命名,是因为它是唯一可以在C中使用的cast。该cast的语法是(NewType)变量。

Whenever this cast is used, it uses one of the following c++ casts (in order):

每当使用此强制转换时,它都会使用以下c++强制转换之一(按顺序):

const_cast<NewType>(variable) static_cast<NewType>(variable) const_cast<NewType>(static_cast<const NewType>(variable)) reinterpret_cast<const NewType>(variable) const_cast<NewType>(reinterpret_cast<const NewType>(variable))

Functional casting is very similar, though as a few restrictions as the result of its syntax: NewType(expression). As a result, only types without spaces can be cast to.

函数式强制转换非常相似,但由于其语法的原因有一些限制:NewType(表达式)。因此,只有不带空格的类型才能被强制转换。

It’s better to use new c++ cast, because s more readable and can be spotted easily anywhere inside a C++ source code and errors will be detected in compile-time, instead in run-time.

最好使用新的c++cast,因为它更具可读性,并且可以在c++源代码中的任何位置轻松发现,错误将在编译时而不是在运行时被检测到。

As this cast can result in unintended reinterpret_cast, it is often considered dangerous.

由于该类型转换可能会导致意外的重新诠释,因此通常被认为是危险的。

1 Casting away constness

A pointer to a const object can be converted to a pointer to non-const object using the const_cast keyword. Here we use const_cast to call a function that is not const-correct. It only accepts a non-const char* argument even though it never writes through the pointer:

指向常量对象的指针可以使用const_cast关键字转换为指向非常量对象的指针。这里我们使用const_cast来调用一个非const-correct的函数。它只接受非常量char*参数,即使它从未通过指针写入:

void bad_strlen(char*); const char* s = "hello, world!"; bad_strlen(s); // compile error bad_strlen(const_cast<char*>(s)); // OK, but it's better to make bad_strlen accept const char*

const_cast to reference type can be used to convert a const-qualified lvalue into a non-const-qualified value.

const_cast引用类型可用于将常量限定左值转换为非常量限定值。

const_cast is dangerous because it makes it impossible for the C++ type system to prevent you from trying to modify a const object. Doing so results in undefined behavior.

const_cast是危险的,因为它使C++类型系统无法阻止您尝试修改const对象。这样做会导致未定义的行为。

const int x = 123; int& mutable_x = const_cast<int&>(x); mutable_x = 456; // may compile, but produces *undefined behavior*

2 Base to derived conversion

A pointer to base class can be converted to a pointer to derived class using static_cast. static_cast does not do any run-time checking and can lead to undefined behaviour when the pointer does not actually point to the desired type.

可以使用static_cast将指向基类的指针转换为指向派生类的指针。static_cast不执行任何运行时检查,当指针实际上没有指向所需类型时,可能会导致未定义的行为。

struct Base {}; struct Derived : Base {}; Derived d; Base* p1 = &d; Derived* p2 = p1; // error; cast required Derived* p3 = static_cast<Derived*>(p1); // OK; p2 now points to Derived object Base b; Base* p4 = &b; Derived* p5 = static_cast<Derived*>(p4); // undefined behaviour since p4 does not // point to a Derived object

Likewise, a reference to base class can be converted to a reference to derived class using static_cast.

同样,对基类的引用可以使用static_cast转换为对派生类的引用。

struct Base {}; struct Derived : Base {}; Derived d; Base& r1 = d; Derived& r2 = r1; // error; cast required Derived& r3 = static_cast<Derived&>(r1); // OK; r3 now refers to Derived object

If the source type is polymorphic, dynamic_cast can be used to perform a base to derived conversion. It performs a run-time check and failure is recoverable instead of producing undefined behaviour. In the pointer case, a null pointer is returned upon failure. In the reference case, an exception is thrown upon failure of type std::bad_cast (or a class derived from std::bad_cast).

如果源类型是多态的,则可以使用dynamic_cast执行从基类到派生类的转换。它执行运行时检查,错误是可恢复的,而不是产生未定义的行为。在指针情况下,失败时返回空指针。在引用情形下,std::bad_cast类型(或从std::bad_cast派生的类)失败时会引发异常。

struct Base { virtual ~Base(); }; // Base is polymorphic struct Derived : Base {}; Base* b1 = new Derived; Derived* d1 = dynamic_cast<Derived*>(b1); // OK; d1 points to Derived object Base* b2 = new Base; Derived* d2 = dynamic_cast<Derived*>(b2); // d2 is a null pointer

3 Conversion between pointer and integer

An object pointer (including void*) or function pointer can be converted to an integer type using reinterpret_cast. This will only compile if the destination type is long enough. The result is implementationdefined and typically yields the numeric address of the byte in memory that the pointer pointers to.

可以使用reinterpret_cast将对象指针(包括void*)或函数指针转换为整数类型。只有在目标类型足够长的情况下,才会编译。结果是实现定义的,通常会生成指针指向的内存字节的数字地址。

Typically, long or unsigned long is long enough to hold any pointer value, but this is not guaranteed by the standard.

通常,long或unsigned long的长度足以容纳任何指针值,但该标准不保证这一点。

If the types std::intptr_t and std::uintptr_t exist, they are guaranteed to be long enough to hold a void* (and hence any pointer to object type). However, they are not guaranteed to be long enough to hold a function pointer.

如果std::intptr_t和std::uintptr_t类型存在,则保证它们的长度足以容纳一个void*(以及任何指向对象类型的指针)。然而,它们不能保证足够长的时间来容纳函数指针。

Similarly, reinterpret_cast can be used to convert an integer type into a pointer type. Again the result is implementation-defined, but a pointer value is guaranteed to be unchanged by a round trip through an integer type. The standard does not guarantee that the value zero is converted to a null pointer.

类似地,reinterpret_cast可用于将整数类型转换为指针类型。同样,结果是实现定义的,但通过整数类型的往返,指针值保证不变。该标准不保证将零值转换为空指针。

void register_callback(void (*fp)(void*), void* arg); // probably a C API void my_callback(void* x) { std::cout << "the value is: " << reinterpret_cast<long>(x); // will probably compile } long x; std::cin >> x; register_callback(my_callback, reinterpret_cast<void*>(x)); // hopefully this doesn't lose information...

4 Conversion by explicit constructor or explicit

A conversion that involves calling an explicit constructor or conversion function can’t be done implicitly. We can request that the conversion be done explicitly using static_cast. The meaning is the same as that of a direct initialization, except that the result is a temporary.

涉及调用显式构造函数或转换函数的转换不能隐式完成。我们可以请求使用static_cast显式地完成转换。其含义与直接初始化相同,只是结果是临时的。

class C { std::unique_ptr<int> p; public: explicit C(int* p) : p(p) {} }; void f(C c); void g(int* p) { f(p); // error: C::C(int*) is explicit f(static_cast<C>(p)); // ok f(C(p)); // equivalent to previous line C c(p); f(c); // error: C is not copyable }

5 Implicit conversion

static_cast can perform any implicit conversion. This use of static_cast can occasionally be useful, such as in the following examples:

static_cast可以执行任何隐式转换。这种static_cast的使用有时会很有用,例如在以下示例中:

When passing arguments to an ellipsis, the “expected” argument type is not statically known, so no implicit conversion will occur.

将参数传递给省略号时,“预期”参数类型不是静态已知的,因此不会发生隐式转换。

const double x = 3.14; printf("%d\n", static_cast<int>(x)); // prints 3 // printf("%d\n", x); // undefined behaviour; printf is expecting an int here // alternative: // const int y = x; printf("%d\n", y);

Without the explicit type conversion, a double object would be passed to the ellipsis, and undefined behaviour would occur.

如果没有显式类型转换,一个double对象将被传递给省略号,并且会发生未定义的行为。

A derived class assignment operator can call a base class assignment operator like so:

派生类赋值运算符可以调用基类赋值运算符,如下所示:

struct Base { /* ... */ }; struct Derived : Base { Derived& operator=(const Derived& other) { static_cast<Base&>(*this) = other; // alternative: // Base& this_base_ref = *this; this_base_ref = other; } };

6 Enum conversions

static_cast can convert from an integer or floating point type to an enumeration type (whether scoped or unscoped), and vice versa. It can also convert between enumeration types.

static_cast可以从整数或浮点类型转换为枚举类型(无论是作用域还是非作用域),反之亦然。它还可以在枚举类型之间转换。

The conversion from an unscoped enumeration type to an arithmetic type is an implicit conversion; it is possible, but not necessary, to use static_cast.

从无范围枚举类型到算术类型的转换是隐式转换;可以使用static_cast,但不是必须的。

When a scoped enumeration type is converted to an arithmetic type:

当作用域枚举类型转换为算术类型时:

If the enum’s value can be represented exactly in the destination type, the result is that value.

如果枚举的值可以在目标类型中精确表示,则结果就是该值。

Otherwise, if the destination type is an integer type, the result is unspecified.

否则,如果目标类型是整数类型,则结果是未指定的。

Otherwise, if the destination type is a floating point type, the result is the same as that of converting to the underlying type and then to the floating point type.

否则,如果目标类型是浮点类型,则结果与转换为基础类型然后再转换为浮点类型的结果相同。

enum class Format { TEXT = 0, PDF = 1000, OTHER = 2000, }; Format f = Format::PDF; int a = f; // error int b = static_cast<int>(f); // ok; b is 1000 char c = static_cast<char>(f); // unspecified, if 1000 doesn't fit into char double d = static_cast<double>(f); // d is 1000.0... probably

When an integer or enumeration type is converted to an enumeration type:

将整数或枚举类型转换为枚举类型时:

If the original value is within the destination enum’s range, the result is that value. Note that this value might be unequal to all enumerators.

如果原始值在目标枚举的范围内,则结果为该值。请注意,此值可能不等于所有枚举数。

Otherwise, the result is unspecified (<= C++14) or undefined (>= C++17).

否则,结果为未指定(<=C++14)或未定义(>=C++17)。

enum Scale { SINGLE = 1, DOUBLE = 2, QUAD = 4 }; Scale s1 = 1; // error Scale s2 = static_cast<Scale>(2); // s2 is DOUBLE Scale s3 = static_cast<Scale>(3); // s3 has value 3, and is not equal to any enumerator Scale s9 = static_cast<Scale>(9); // unspecified value in C++14; UB in C++17

When a floating point type is converted to an enumeration type, the result is the same as converting to the enum’s underlying type and then to the enum type.

将浮点类型转换为枚举类型时,结果与先转换为枚举的基础类型,然后再转换为枚举类型相同。

enum Direction { UP = 0, LEFT = 1, DOWN = 2, RIGHT = 3, }; Direction d = static_cast<Direction>(3.14); // d is RIGHT

7 Derived to base conversion for pointers to members

A pointer to member of derived class can be converted to a pointer to member of base class using static_cast.

可以使用static_cast将指向派生类成员的指针转换为指向基类成员的指针。

The types pointed to must match.

指向的类型必须匹配。

If the operand is a null pointer to member value, the result is also a null pointer to member value.

如果操作数是指向成员值的空指针,则结果也是指向成员值的空指针。

Otherwise, the conversion is only valid if the member pointed to by the operand actually exists in the destination class, or if the destination class is a base or derived class of the class containing the member pointed to by the operand. static_cast does not check for validity. If the conversion is not valid, the behaviour is undefined.

否则,只有当操作数指向的成员实际存在于目标类中,或者目标类是包含操作数指向的成员的类的基类或派生类时,转换才有效。static_cast不检查有效性。如果转换无效,则行为未定义。

struct A {}; struct B { int x; }; struct C : A, B { int y; double z; }; int B::*p1 = &B::x; int C::*p2 = p1; // ok; implicit conversion int B::*p3 = p2; // error int B::*p4 = static_cast<int B::*>(p2); // ok; p4 is equal to p1 int A::*p5 = static_cast<int A::*>(p2); // undefined; p2 points to x, which is a member // of the unrelated class B double C::*p6 = &C::z; double A::*p7 = static_cast<double A::*>(p6); // ok, even though A doesn't contain z int A::*p8 = static_cast<int A::*>(p6); // error: types don't match

8 void* to T*

In C++, void* cannot be implicitly converted to T* where T is an object type. Instead, static_cast should be used to perform the conversion explicitly. If the operand actually points to a T object, the result points to that object.

在C++中,void*不能隐式转换为T*,其中T是对象类型。相反,应该使用static_cast显式地执行转换。如果操作数实际指向一个T对象,则结果指向该对象。

Otherwise, the result is unspecified.

否则,结果未明。

Even if the operand does not point to a T object, as long as the operand points to a byte whose address is properly aligned for the type T, the result of the conversion points to the same byte.

即使操作数不指向T对象,只要操作数指向的字节的地址与类型T正确对齐,转换结果也会指向同一字节。

// allocating an array of 100 ints, the hard way int* a = malloc(100*sizeof(*a)); // error; malloc returns void* int* a = static_cast<int*>(malloc(100*sizeof(*a))); // ok // int* a = new int[100]; // no cast needed // std::vector<int> a(100); // better const char c = '!'; const void* p1 = &c; const char* p2 = p1; // error const char* p3 = static_cast<const char*>(p1); // ok; p3 points to c const int* p4 = static_cast<const int*>(p1); // unspecified in C++03; // possibly unspecified in C++11 if // alignof(int) > alignof(char) char* p5 = static_cast<char*>(p1); // error: casting away constness

9 Type punning conversion

A pointer (resp. reference) to an object type can be converted to a pointer (resp. reference) to any other object type using reinterpret_cast. This does not call any constructors or conversion functions.

可以使用reinterpret_cast将指向对象类型的指针(响应引用)转换为指向任何其他对象类型的指针(响应引用)。这不会调用任何构造函数或转换函数。

int x = 42; char* p = static_cast<char*>(&x); // error: static_cast cannot perform this conversion char* p = reinterpret_cast<char*>(&x); // OK *p = 'z'; // maybe this modifies x (see below)

The result of reinterpret_cast represents the same address as the operand, provided that the address is appropriately aligned for the destination type. Otherwise, the result is unspecified.

reinterpret_cast的结果表示与操作数相同的地址,前提是地址与目标类型正确对齐。否则,结果未明。

int x = 42; char& r = reinterpret_cast<char&>(x); const void* px = &x; const void* pr = &r; assert(px == pr); // should never fire

The result of reinterpret_cast is unspecified, except that a pointer (resp. reference) will survive a round trip from the source type to the destination type and back, as long as the destination type’s alignment requirement is not stricter than that of the source type.

reinterpret_cast的结果未指定,但指针(对应的引用)将在从源类型到目标类型的往返过程中幸存,只要目标类型的对齐要求不比源类型的对齐要求更严格。

int x = 123; unsigned int& r1 = reinterpret_cast<unsigned int&>(x); int& r2 = reinterpret_cast<int&>(r1); r2 = 456; // sets x to 456

On most implementations, reinterpret_cast does not change the address, but this requirement was not standardized until C++11.

在大多数实现中,reinterpret_cast不会更改地址,但直到C++11,这个要求才被标准化。

reinterpret_cast can also be used to convert from one pointer-to-data-member type to another, or one pointerto-member-function type to another.

reinterpret_cast还可用于从一个指向数据成员类型的指针转换为另一个,或从一个指向成员函数类型的指针转换为另一个。

Use of reinterpret_cast is considered dangerous because reading or writing through a pointer or reference obtained using reinterpret_cast may trigger undefined behaviour when the source and destination types are unrelated.

使用reinterpret_cast被认为是危险的,因为当源类型和目标类型不相关时,通过使用reinterpret_cast获得的指针或引用进行读写可能会触发未定义的行为。

ref:

《++ Notes For Professionals》

-End-

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/53985.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信