[C++] 关于C++的cast

1、前言】

 

前一段时间给人回答一个问题回答错了,问题是dynamic_cast的耗时问题。我回答说这个只是字节的拷贝,没有其它耗时的,后来才知道由于继承关系有虚表vtable,里面涉及到继承链的转换,type识别。为了弥补,特意从《Working Draft, Standard forProgrammingLanguage C++ n3242中摘抄一段,翻译过来,算是学习的一个积累吧。

如果有翻译不当的地方,请指正!谢谢!

 

1.1>如果'>'符号放在某个typeid后面,并且作为一个类型放在*_cast<>的内部,很可能造成两个连续的'>'被认为是移位'>>',例如

vector<int*> v1;
vector<int*> v2 = static_cast<vector<int*>>(v1);    // ill-formed
vector<int*> v2 = static_cast< vector<int*> >(v1);  // OK

1.2> cv-qualify翻译成cv-限定词,c表示constv表示volatile,如果

int a;
const int b;
volatile  c;

那么我们可以说bca更加cv-qualified。后面加cv前缀的都表示cv是可选项,并不表示必选。

 

1.3>可能有人对rvalue reference(右值引用)不太了解,这是标准最近才加入的,请google之。

 

1.4>最终派生对象(most derived object——an object of a most derived class type),我的理解是一个对象在声明时是一个派生类对象,但是可能用了基类的指针bptr指向它,那么bptr的“最终派生对象”就是实际的派生类对象。引用类似。

 

1.5>子对象(subobject),从内存模型来看,一个派生类对象包含了一个基类对象,以及自己附加的一些属性信息,那么派生类对象里面的基类相关部分就可以称作子对象。唯一的子对象(unique subobject)是指,派生类对象里只包含一个该基类的子对象,例如:

class Base{};
class D1 : public Base {};
class D2 : public Base {};
class X : public D1, public D2 {};
D1  obj_d1;
D2  obj_d2;
X   obj_x;

其中

obj_d1包含一个Base类型的子对象,唯一;

obj_d2包含一个Base类型的子对象,唯一;

obj_x包含一个D1类型的子对象,唯一;包含一个D2类型的子对象,唯一;但是包含两个Base类型的子对象,不唯一。所以它可以向D1D2转换,却不能向Base转换,否则会造成不明确(ambiguous)。

 

 

1.6>完全类型(complete class type),是指在使用该类型时,该类型已经定义完全。例如:

classA{ int a; }; // definition of A

Aobja;   // now A iscomplete class type

classB;  // declaration of B

B*objb;  // now B is incomplete class type

classB{ int b; }; // definition of B

 

1.7>类型图

expression

/        \

glvalue    rvalue

/     \    /   \

lvalue  xvalue  prvalue

详细解释请参看http://blog.csdn.net/zwvista/article/details/5459774

 

1.8>虚基类(virtual base class

当某个基类通过多条继承路径被某个派生类继承,那么就会存在基类的多个子对象,为了只保留一份,需要将该基类的继承关系声明为virtual的。例如:

struct B { virtual void f() {} };
struct D1 : virtual public B { };
struct D2 : virtual public B { };
struct X : public D1, public D2 { };  // X object will contain only one subobject of B

详细解释请参看http://baike.baidu.com/view/1267123.htm

 

2dynamic_cast<T>(v)

 

2.0> dynamic_cast只针对多态类型的转换,这是运行时才能确定的,所以叫做dynamic,如果简单的结构体继承是无法体现多态的,多态一定要有虚函数,这样才会有虚表(虚表存放虚函数的指针以及类型信息)。

 

2.1> T应当是一个完全类型(1.6)的指针或者引用,或者是cv void*类型(cv1.2)。dynamic_cast不会去掉const属性。

[Tshall be a pointeror reference to a complete class type, or “pointer to cv void.” The dynamic_cast operatorshall notcast away constness]

 

2.2>如果T是指针类型,那么v应当是完全类型的指针的prvalue,结果是T类型prvalue;如果Tlvalue引用类型,那么v应当是完全类型的lvalue,结果是T类型的lvalue;如果Trvalue引用类型,那么v应当是一个完全类型的表达式,结果是类型Txvalue

[If T is a pointer type, v shall be a prvalue of a pointer tocomplete class type, and the result is a prvalue of type T. If T isan lvalue reference type, v shall be an lvalue of a complete class type, andthe result is an lvalue of thetype referred to by T. If T is an rvalue reference type, v shall be anexpression having a completeclass type, and the result is an xvalue of the type referred to by T.]

 

2.3>如果Tv类型完全一样,或者基本一致,除了Tv更加cv-qualified,那么结果就是v。概括为仅在需要时转换。

[If the type of v is the same as T, or it is the same as T exceptthat the class object type in T is more cv-qualifiedthan the class object type in v, the result is v (converted if necessary).]

 

2.4>如果v是指针NULL,那么结果就是(T*)NULL

[If the value of v is a null pointer value in the pointer case, theresult is the null pointer value of type T.]

 

2.5>如果T是基类B的指针,v是派生类D的指针,那么结果就是一个值为v的指针,指向D对象的唯一的B子对象(1.5)。引用的情况相似。如果Tlvalue引用,结果是lvalue;如果Trvalue引用,结果是xvalue。不过无论是指针还是引用的情况,如果vT更加cv-qualified,或者基类对于派生类是不可访问的(private继承)或者是不明确的,程序都是不合语法的。

[If T is “pointer to cv1 B” and v has type “pointer to cv2 D” suchthat B is a base class of D, the result is a pointer to the unique B subobject of the D object pointed to by v. Similarly, if T is “reference to cv1 B” andv has type cv2 D such that B is a base class of D, the result is the unique B subobject of the D object referredto by v. The result is an lvalue if T is an lvalue reference, or anxvalue if T is an rvalue reference. In both the pointer and reference cases, the program is ill-formed if cv2has greater cv-qualification than cv1 or if B is an inaccessible or ambiguous base class of D.]

 

struct B { virtual void f() {} };
struct D1 : public B { };
struct D2 : public B { };
struct D3 : private B { };
struct X : public D1, public D2 { };
void foo1(D1* dp) {
	B* bp = dynamic_cast<B*>(dp); // OK, equivalent to B* bp = dp;
}
void foo2(X* dp) {
	B* bp = dynamic_cast<B*>(dp); // error, ambiguous base class
}
void foo3(D3* dp) {
	B* bp = dynamic_cast<B*>(dp); // error, inaccessible base class
}
void foo4(const D2* dp) {
	B* bp = dynamic_cast<B*>(dp); // error, "const D2*" is more cv-qualified than "B*"
}


2.6>其它情况,v应当是一个多态类型的指针或者lvalue。(这暗示v是有限制的,dynamic_cast不是什么都可以转换的)

[Otherwise, v shall be a pointer to or an lvalue of a polymorphic type]

 

2.7>如果Tcv void指针,那么结果是v指向的最终派生对象(most derived object)。否则运行时会进行检查,看能否合法进行从v到类型T的转换。

[If T is “pointer to cv void,” then the result is a pointer to themost derived object pointed to by v. Otherwise,a run-time check is applied to see if the object pointed or referred to by v can be converted to the typepointed or referred to by T.]

 

2.8>假设T指向或引用class C,那么运行时判断逻辑如下:

a>如果v指向或引用的最终派生对象内,v指向或引用一个C对象的某个公有基类的子对象(注意这暗示最终派生对象包含至少1C对象),并且只有一个C对象是继承自该子对象,那么结果指向或引用C对象。(down-cast

b>如果v指向或引用最终派生类型的基类的子对象,C也是最终派生对象的基类,并且C是明确的(unambiguous)和公有的(public),那么结果指向或引用C子对象(间接关系,先从v找到最终派生对象,再找到Cdown-up-cast

c>否则,运行时检测失败

[If C is the class type to which T points or refers, the run-timecheck logically executes as follows:

—If, in the most derived object pointed (referred) to by v, v points (refers) to a public base class subobject of a C object, and if only one object of type C is derived from the subobject pointed (referred) to by v the result points (refers) to that C object.

—Otherwise, if v points (refers) to a public base class subobject of the most derived object, and the typeof the most derived object has a base class, of type C, that is unambiguous andpublic, the result points(refers) to the C subobject of the most derived object.

— Otherwise, the run-time check fails.]

 

struct B { virtual void f() {} };
struct D1 : public B { };
struct D2 : public B { };
struct D3 : private B { };
struct D4 : public D1 { };
struct X : public D1, public D2 { };

D1*  obj1 = new D4();
D4*  obj4 = dynamic_cast< D4* >(obj1);  // OK, down-cast
D1*  obj12 = new X();
D2*  obj21 = dynamic_cast< D2* >(obj12);  // OK, down-up-cast
X*   objx  = dynamic_cast< X* >(obj12);   // OK, down-cast
B*   obj0  = dynamic_cast< B* >(objx);    // error, ambiguous

2.9>一个失败的指针cast会返回(T*)NULL,而失败的引用cast则会抛出异常std::bad_cast

示例

class A { virtual void f(); };
class B { virtual void g(); };
class D : public virtual A, private B { };
void g() {
	D d;
	B* bp = (B*)&d;                // cast needed to break protection
	A* ap = &d;                    // public derivation, no cast needed
	D& dr = dynamic_cast<D&>(*bp); // fails
	ap = dynamic_cast<A*>(bp);     // fails
	bp = dynamic_cast<B*>(ap);     // fails
	ap = dynamic_cast<A*>(&d);     // succeeds
	bp = dynamic_cast<B*>(&d);     // ill-formed (not a run-time check)
}
class E : public D, public B { };
class F : public E, public D { };
void h() {
	F f;
	A* ap = &f;                    // succeeds: finds unique A
	D* dp = dynamic_cast<D*>(ap);  // fails: yields 0
	                               // f has two D subobjects
	E* ep = (E*)ap;                // ill-formed: cast from virtual base
	E* ep1 = dynamic_cast<E*>(ap); // succeeds
}

 

3static_cast<T>(v)

 

3.1>将表达式v转化为类型T。如果T是对lvalue引用或函数类型的rvalue引用,结果是lvalue;如果T是对象类型的rvalue引用,那么结果是xvalue;否则结果是prvaluestatic_cast不能去掉对象const属性。

[The result of the expression static_cast<T>(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is anxvalue; otherwise, the result is a prvalue. The static_cast operator shall not cast away constness]

 

3.2>对于基类B和派生类D,如果基类B既不是D的虚基类(1.8),也不是D的虚基类的基类,并且D指针到B指针的合法标准转换存在,并且cv属性不变或增强,那么就可以将基类Blvalue转化为派生类D的引用。同等条件下,基类Bxvalue可以转化为派生类的rvalue引用。如果待转换的B对象本来就是D对象的一个子对象,那么转化后,结果就引用整个D对象,否则转化结果是未定义的。

[An lvalue of type “cv1 B,” where B is a class type, can be cast to type “reference to cv2 D,” where D is a classderived (Clause 10) from B, if a valid standard conversion from“pointer to D” to “pointer to B” exists (4.10),cv2 is the same cv-qualification as, or greater cv-qualificationthan, cv1, and B is neither a virtual base classof D nor a base class of a virtual base class of D. The result hastype “cv2 D.” An xvalue of type “cv1 B” maybe cast to type “rvalue reference to cv2 D” with the sameconstraints as for an lvalue of type “cv1 B.” If theobject of type “cv1 B” is actually a subobject of an object of typeD, the result refers to the enclosing objectof type D. Otherwise, the result of the cast is undefined.]

 

struct B { };
struct D : public B { };
D d;
B &br = d;
static_cast<D&>(br); // produces lvalue to the original d object


3.3> 如果相对于类型 T1 T2 是引用兼容的( reference-compatible ),那么 T1 glvalue 可以转化为 T2 rvalue 引用。结果引用对象本身或者对象内特定基类的子对象。如果 T2 T1 的不可访问的或者是不明确的基类,那么程序是不合语法的( ill-formed

[A glvalue of type “cv1 T1” can be cast to type “rvalue reference to cv2 T2” if “cv2 T2” is reference-compatible with “cv1 T1” (8.5.3). The result refers to the object or the specified base class subobject thereof. If T2 isan inaccessible (Clause 11) or ambiguous (10.2) base class of T1, aprogram that necessitates such a cast isill-formed.]

 

3.4>否则,对于表达式e,如果T t(e);是合法的声明,那么可以使用static_cast<T>(e)e转化为T类型,不过会引入临时变量t。这样的显式转化就和直接声明并初始化临时变量,然后使用临时变量的效果是一样的。当且仅当初始化时将e作为glvalue,那e才会被当做是glvalue

[Otherwise, an expression e can be explicitly converted to a type Tusing a static_cast of the form static_-cast<T>(e)if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The effect of such anexplicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The expression e isused as a glvalue if and only if the initialization uses it as a glvalue.]

 

3.5>否则,所有转换的可能都在下面列举,不可能有其它的static_cast用法了。

[Otherwise, the static_cast shall perform one of the conversions listed below. No other conversion shall be performed explicitly using a static_cast.]

 

3.6>任何表达式都可以显式转换为cv void,表达式的值就被丢弃了。(注意:如果是表达式结果一个临时对象,临时对象的析构函数在当时又没有被调用,那么临时变量的值不会被丢弃,以备将来调用析构函数时使用)。lvalue-to-rvaluearray-to-pointerfunction-to-pointer不适用于这种表达式。

[Any expression can be explicitly converted to type cv void. The expression value is discarded. [ Note: however, if thevalue is in a temporary object (12.2), the destructor for that object is not executed until the usual time,and the value of the object is preserved for the purpose of executing the destructor. —end note ] The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3)standard conversions are not applied to the expression.]

 

3.7> 除去lvalue-to-rvaluearray-to-pointerfunction-to-pointernull pointernull member pointerbool转换,其它标准转换的逆向转换可以显式调用static_cast。如果程序用static_cast进行不合语法的标准转换的逆向转换,那么程序是不合语法的。

[The inverse of any standard conversion sequence (Clause 4) not containing an lvalue-to-rvalue (4.1), array-to-pointer(4.2), function-to-pointer (4.3), null pointer (4.10), null member pointer(4.11), or boolean (4.12) conversion, can be performed explicitly using static_cast. A program is ill-formed if it uses static_castto perform the inverse of an ill-formed standard conversion sequence.]

示例:

struct B { };
struct D : private B { };
void f() {
	static_cast<D*>((B*)0);             // Error: B is a private base of D.
	static_cast<int B::*>((int D::*)0); // Error: B is a private base of D.
}


3.8>lvalue-to-rvaluearray-to-pointerfunction-to-pointer适用于运算对象,这样的static_cast也同样不能去const属性,下面是一些额外规则:

[The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) conversions are applied to the operand. Such a static_cast is subject to the restriction that the explicitconversion does not cast away constness (5.2.11), and the following additional rules for specific cases:]

 

3.9>作用域内的枚举类型可以转换为整数,如果指示类型能够表示原来的类型,那么值不变,否则结果是未定义的。作用域内枚举类型也可以转化为浮点数,结果就是将原值转化为浮点数。

[A value of a scoped enumeration type (7.2) can be explicitly converted to an integral type. The value is unchanged if the original value can be represented by the specified type. Otherwise, the resulting value is unspecified. A value of a scoped enumeration type can also be explicitly converted to a floating-point type; the result is the same as that of converting from the original value to the floating-point type.]


3.10>整型或枚举类型可以转换到其它枚举类型,如果原值的取值范围在目标枚举变量的取值范围内,值不变,否则结果是未定义的。

[A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise,the resulting enumeration value is unspecified.]

 

3.11>对于基类B和派生类D,如果D指针到B指针存在合法的标准转换,并且转换后cv属性不变或增强,并且B既不是D的虚基类也不是D的虚基类的基类,那么可以将B指针的prvalue转换到D指针的prvalueNULL指针会被直接转换为目标类型的NULL指针。如果待转换的B指针的prvalue本来就指向D对象的一个B子对象,那么转化后,结果指针就指向整个D对象,否则转化结果是未定义的。

[A prvalue of type “pointer to cv1 B,” where B is a class type, canbe converted to a prvalue of type “pointer to cv2 D,” where D is a class derived (Clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists (4.10), cv2 is the same cv-qualification as,or greater cv-qualification than, cv1, and B is neither a virtual base class of D nor a base class of a virtual base class of D. The null pointer value (4.10)is converted to the null pointer value of the destination type. If the prvalue of type “pointer to cv1 B” points to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.]

 

3.12>对于基类B和派生类D,都含有T类型成员,如果存在从B成员的指针到D成员的指针的合法的标准转换,并且转换后cv属性不变或增强,那么可以将D成员的指针的prvalue转换为B成员的指针的prvalueNULL成员指针会被直接转换为目标类型的NULL成员指针。

如果B含有原始成员,或者是含有原始成员类的基类或者派生类,那么结果的成员指针指向该原始成员,否则结果是未定义的。(注意,尽管基类不必须包含原始成员,但指针指向的对象成员所在的对象的动态类型必须包含原始成员)

[A prvalue of type “pointer to member of D of type cv1 T” can be converted to a prvalue of type “pointer to member of B” oftype cv2 T, where B is a base class (Clause 10) of D, if a valid standard conversion from “pointer to member of B of type T” to “pointer to member of D of type T” exists (4.11), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.The null member pointer value (4.11) is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [ Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see 5.5. —endnote ]]

 

3.13>从指向cv1 void的指针的prvalue可以转换到cv2 T的指针的prvalue,如果cv2cv-qualification大于等于cv1的。NULL指针会被直接转换为目标类型的NULL指针。如果对象指针转化为void*又转化回来,可能会改变cv属性,但是值是不变的。

[A prvalue of type “pointer to cv1 void” can be converted to aprvalue of type “pointer to cv2 T,” whereT is an object type and cv2 is the same cv-qualification as, orgreater cv-qualification than, cv1. The null pointer value isconverted to the null pointer value of the destination type. A value of typepointer toobjectconverted to “pointer to cv void” and back,possibly with different cv-qualification, shall have its originalvalue.]

 

示例:

T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true.

 

4reinterpret_cast<T>(v)

 

4.1>如果Tlvalue引用类型或者函数的rvalue引用类型,结果是lvalue;如果T是对象的rvalue引用类型,结果是xvalue;否则结果是prvalue,并且标准转换(lvalue-to-rvaluearray-to-pointerfunction-to-pointer)会作用于表达式v上。显式调用reinterpret_cast适用于下列情况,其它情况都不能用reinterpret_cast

[The result of the expression reinterpret_cast<T>(v) is theresult of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue and the lvalue-to-rvalue(4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the expression v. Conversions that can beperformed explicitly using reinterpret_cast are listed below. No

other conversion can be performed explicitly using reinterpret_cast.]

 

4.2> reinterpret_cast不会去掉const属性。由整数、枚举、指针、成员指针构成的表达式可以显式转换到该表达式的类型,这种转换取决于操作数的值。

[The reinterpret_cast operator shall not cast away constness(5.2.11). An expression of integral, enumeration, pointer,or pointer-to-member type can be explicitly converted to its own type; such acast yields thevalue of itsoperand.]

 

4.3>注意:用reinterpret_cast进行映射,可能会产生一个与原来值不同的表示。见4.4,我的理解是有可能某些情况下,因为字节序的不同,可能会有不同的映射,但是reinterpret_cast不会进行这种特殊化的映射。

[ Note: Themapping performed by reinterpret_cast might, or might not, produce a representation different from the originalvalue. —end note ]

 

4.4>指针可以显式转化为任意能容纳它的整型。映射函数是由实现定义的。(注意:这应该是了解机器取址结构的人能够意料的)。std::nullptr_t类型的值可以转化为整型,转化的含义和正确性等同于从(void*)0转换到整型。(注意:不能用reinterpret_cast将其它任意类型转换为std::nullptr_t

[A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined.[ Note: It is intended to be unsurprising to those who know the addressing structure of the underlying machine. —end note ] A value of type std::nullptr_t can be converted to an integral type; the conversion has the same meaning and validity as a conversion of (void*)0 to the integral type.[ Note: A reinterpret_cast cannot be used to convert a value of any type to the typestd::nullptr_t.—end note ]]

 

4.5>一个整型或者枚举类型的值可以显式转换到指针。一个指针转换到一个足够大小的整型(如果实现里存在这样的转换)然后再转回同样的指针类型,值不变;指针和整型之间的映射是实现时定义的。(注意:除非是3.7.4.3的情况,否则结果不会是一个安全继承的指针)

[A value of integral type or enumeration type can be explicitlyconverted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined. [ Note: Except as described in 3.7.4.3, the result of such a conversion will not be a safely-derived pointer

value.—end note ]]

 

4.6>一个函数指针可以显示转换到另一个类型的函数指针。通过函数指针调用一个和定义时类型不同的函数,那么结果是未定义的。从一个函数指针转换到另一个函数指针再逆向转换回来,如果是prvalue,那么得到的值是原来的值,否则结果是未指定的。

[A pointer to a function can be explicitly converted to a pointer toa function of a different type. The effect of calling a function through a pointer to a function type (8.3.5)that is not the same as the type used in the definition of the function is undefined. Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [ Note: see also 4.10 for more details of pointer conversions. —end note ]]

 

4.7>一个对象指针可以显示转换到另一个类型对象的指针。如果对于两种类型T1T2都是标准布局类型,并且T2的对齐要求不比T1更严格,那么从T1指针的prvalue转换到T2指针的prvalue,结果就是static_cast<cvT2*>(static_cast<cvvoid*>(v))。在上面的情况下,分别进行正向和逆向转换后,结果还是原来指针的值。对于其他种类的指针转换结果是未指定的。

[A pointer to an object can be explicitly converted to a pointer to adifferent object type. When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cvT2*>(static_cast<cvvoid*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1. Converting a prvalue of type “pointer to T1”to the type “pointer to T2”(where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointerconversion is unspecified.]

 

4.8>函数指针与对象指针之间的相互转换在某些情况下是支持的。这样转换的具体含义是由实现定义的,如果实现支持两个方向的转换,从一个类型的prvalue转换到另一个类型然后在转换回来(或许有不同的cv属性),应当不改变原来的值。

[Converting a pointer to a function into a pointer to an object type or vice versa is conditionally-supported. The meaning of such a conversion is implementation-defined, except that if an implementation supports conversionsin both directions, converting a prvalue of one type to the other type and back, possibly with different cv-qualification, shall yield the original pointer value.]

 

4.9> NULL指针会被转换为结果类型的NULL指针。(注意:std::nullptr_t类型的NULL指针常量不能被转换到一个指针类型,一个null指针常量或者是一个整型没有必要转换到一个NULL指针值)

[The null pointer value (4.10) is converted to the null pointer value of the destination type. [ Note: A null pointer constant of type std::nullptr_t cannot be converted to a pointer type, and a null pointer constant of integral type is not necessarily converted to a null pointer value. —end note ]]

 

 

4.10> T1X类的一个成员类型,T2Y类的一个成员类型,如果T1T2都是函数类型或者都是对象类型,那么可以显式从X的成员指针的prvalue转换到Y的成员指针的prvalueNULL成员指针会被转换为结果类型的NULL成员指针。这样转换的结果是未指定的,除了以下情况:

a>从一个成员函数指针的prvalue转换到另一个类型的成员函数指针的prvalue再转换回来,那么结果的值不变

b>从一个成员变量的指针的prvalue转换到另一个成员变量的指针的prvalue再转换回来(T2的对齐要求不强于T1),结果指针的值不变。

[A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types. The null member pointer value (4.11) is converted to the null member pointer value of the destination type. The result of this conversion is unspecified, except in the following cases:

— converting a prvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value.

— converting a prvalue of type “pointer to data member of X of type T1” to the type “pointer to datamember of Y of type T2” (where the alignment requirements of T2 are no stricter than those of T1)and back to its original type yields the original pointer to member value.]

 

4.11>对于类型T1T2,如果可以用reinterpret_castT1指针转换为T2指针,那么可以将T1lvalue表达式转换为T2的引用。也就是说,在使用内建的'&''*'操作符时,reinterpret_cast<T&>(x)的效果等同于*reinterpret_cast<T*>(&x)(并且和reinterpret_cast<T&&>(x)效果相似)。结果引用原来lvalue的对象,但是拥有了不同的类型。如果Tlvalue引用或者是函数类型的rvalue引用,结果是lvalue,如果T是对象类型的rvalue引用,结果是xvalue。不会创建临时变量,不会有拷贝,构造函数和转换函数不会被调用。

[An lvalue expression of type T1 can be cast to the type “referenceto T2” if an expression of type “pointer toT1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a reference cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with the built-in & and * operators (and similarly for reinterpret_cast<T&&>(x)). The result refers to the same object as the source lvalue, but with a different type. The result is an lvalue for an lvalue reference type oran rvalue reference to function type and an xvalue for an rvalue reference to object type. No temporary is created, no copy is made, and constructors(12.1) or conversion functions (12.3) are not called.]

 

 5const_cast<T>(v)

 

5.1>如果T是对象类型的lvalue引用,结果是lvalue;如果T是对象类型的rvalue引用,结果是xvalue;否则结果是prvalue。并且标准转换(lvalue-to-rvalue,array-to-pointer, and function-to-pointer)会作用于表达式v上。可以显式调用const_cast的情况列举如下,其它情况不应当用const_cast

[The result of the expression const_cast<T>(v) is of type T. If T is an lvalue reference to object type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue and the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer(4.3) standard conversions are performed on the expression v. Conversions that can be performed explicitly using const_-cast are listed below. No other conversion shall be performed explicitly using const_cast.]

 

5.2>注意:一个表达式可以用const_cast转换到自己本身的类型。

[ Note: Subject to the restrictions in this section, an expression may be cast to its own typeusing a const_-cast operator.—end note ]

 

5.3>对于两种指针T1T2T1T类型指针的指针的指针,T2T类型的指针的指针的指针,每一层指针前都有cv属性限定(这些属性可以不同),T是任意类型或者是void类型,那么一个T1prvalue可以转换到T2prvalue,指针const_cast的转换结果指向原来的对象。(我认为这里应该用points而不是refers

[For two pointer types T1 and T2 where

T1 is cv1,0 pointer to cv1,1 pointer to· · · cv1,n1 pointer to cv1,n T

and

T2 is cv2,0 pointer to cv2,1 pointer to· · · cv2,n1 pointer to cv2,n T

where T is any object type or the void type and where cv1,k and cv2,k may be different cv-qualifications, a prvalue of type T1 may be explicitly converted to the type T2 using a const_cast. The result of a pointer const_cast refers to the original object.]

 

5.4>对于两种对象类型T1T2,如果const_cast能够从T1指针转换到T2指针,那么以下转换也可以进行:

a>使用const_cast<T2&>可以将T1lvalue转换为T2lvalue

b>使用const_cast<T2&&>可以将T1glvalue转换为T2xvalue

c>如果T1是一个类,那么一个T1prvalue可以转换为T2xvalue

引用的const_cast的结果引用原来的对象。

[For two object types T1 and T2, if a pointer to T1 can be explicitly converted to the type “pointer to T2”using a const_cast, then the following conversions can also be made:

—an lvalue of type T1 can be explicitly converted to an lvalue of type T2 using the cast const_cast<T2&>;

—a glvalue of type T1 can be explicitly converted to an xvalue of type T2 using the cast const_cast<T2&&>; and

— if T1 is a class type, a prvalue of type T1 can be explicitly converted to an xvalue of type T2 using the cast const_cast<T2&&>.

The result of a reference const_cast refers to the original object.]

 

5.5>对于const_cast,包含数据成员指针、多重数据成员指针、多重数据混合(成员和非成员)指针,const_cast的规则和对普通指针转换的规则是一致的,当增加或者减少cv属性时,成员指针的成员这个属性是被忽略的。const_cast结果成员指针和原始的(未经转换的)成员指针引用同样的成员。

[For a const_cast involving pointers to data members, multi-level pointers to data members and multi-level mixed pointers and pointers to data members (4.4), the rules for const_cast are the same as those used for pointers; the “member” aspect of a pointer to member is ignored when determining where the cv-qualifiers are added or removed by the const_cast. The result of a pointer to data member const_cast refers to the same member as the original (uncast) pointer to data member.]

 

5.6> NULL指针或者NULL成员指针都会被转换到目标类型的NULL指针。

[A null pointer value (4.10) is converted to the null pointer value of the destination type. The null member pointer value (4.11) is converted to the null member pointer value of the destination type.]

 

5.7>注意:依赖于对象类型,通过const_cast获得的指针、lvalue或者数据成员指针,转换了const属性,执行的写操作可能会产生未定义的行为。

[Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier may produce undefined behavior(7.1.6.1). —end note ]

 

5.8>下列规则定义了去除const属性的规则,其中TnXn表示类型,对于两种指针类型:

X1T1的指针的指针的指针(共N重),T1不是指针类型

X2T1的指针的指针的指针(共M重),T2不是指针类型

KNM的较小值

X1X2的转换去掉了const属性,如果对于非指针类型T,不存在下列隐式转换:

T的指针的指针的指针(共K重),cv属性对应X1的前Kcv属性

T的指针的指针的指针(共K重),cv属性对应X2的前Kcv属性

[The following rules define the process known as casting away constness. In these rules Tn and Xn represent types. For two pointer types:

X1 is T1cv1,1 * · · · cv1,N * where T1 is not a pointer type

X2 is T2cv2,1 * · · · cv2,M * where T2 is not a pointer type

K is min(N,M)

casting from X1 toX2 casts away constness if, for a non-pointer type T there does not exist an implicit conversion (Clause4) from:

Tcv1,(NK+1) *cv1,(NK+2) * · · · cv1,N *

to

Tcv2,(MK+1) *cv2,(MK+2) * · · · cv2,M *

]

 

5.9>T1lvalue转换到T2lvalue,使用lvalue引用转换;或者从T1的表达式转换到T2xvalue,使用rvalue引用转换

上述两种情况,如果从T1指针的prvalue转换到T2指针的prvalue失去了const属性,那么上面两种情况也会丢掉const属性

[Casting from an lvalue of type T1 to an lvalue of type T2 using an lvalue reference cast or casting from an expression of type T1 to an xvalue of type T2 using an rvalue reference cast casts away constness if a cast from a prvalue of type “pointer to T1” to the type “pointer to T2”casts away constness.]

 

5.10>如果从T1指针的prvalue转换到T2指针的prvalue失去了const属性,那么从X的类型为T1的数据成员指针的prvalue转换到Y的类型为T2的数据成员指针的prvalue也会丢弃const属性。

[Casting from a prvalue of type “pointer to data member of X of type T1” to the type “pointer to data member of Y of type T2” casts away constness if a cast from a prvalue of type “pointer to T1” to the type “pointerto T2” casts away constness.]

 

5.11>对于多重成员指针,或者多重混合(成员与非成员)指针,决定是否去除const属性不会考虑到“成员”这个方面。

[For multi-level pointer to members and multi-level mixed pointers and pointer to members (4.4), the “member” aspect of a pointer to member level is ignored when determining if a const cv-qualifier has been cast away.]

 

5.12>注意:有时候仅用const_cast改变cv属性是不行的,例如,函数指针之间的转换就不被支持,因为这样的转换导致被使用的值产生未定义行为。同样的道理,成员函数指针之间的转换,尤其是,从一个const成员函数指针到一个非const成员函数指针的转换,就不被支持。

[Note: some conversions which involve only changes in cv-qualification cannot be done using const_cast. For instance, conversions between pointers to functions are not covered because such conversions lead to values whose use causes undefined behavior. For the same reasons, conversions between pointers to member functions,and in particular, the conversion from apointer to a const member function to a pointer to a non-const member function, are not covered. —end note ]


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值