static_cast
用隐式和用户定义转换的组合在类型间转换。
语法
static_cast <new_type> (expression)
返回 new_type
类型的值。
解释
唯有下列转换能用 static_cast
执行,但若转换会转型走常量性或易变性则亦不允许。
若存在从 expression 到 new_type 的隐式转换序列,或者若针对以 expression 到 new_type 类型的对象或引用所进行的直接初始化的重载决议,找到至少一个可行函数,则
static_cast <new_type> (expression)
返回如同以new_type Temp(expression);
所初始化的一个虚构变量Temp
,它可能涉及隐式转换,对 new_type 的构造函数的调用,或对用户定义转换运算符的调用。对于非引用的 new_type,static_cast 纯右值表达式的结果对象是其直接初始化的对象。 (C++17 起)若 new_type 是某类类型
D
的左值或指向它的指针纯右值,而 expression 的类型是到其非虚基类B
的指针或引用,则static_cast
进行向下转型(downcast)。若B
是D
的有歧义、不可访问或虚的基类(或虚基类的基类),则此向下转型非良构。这种static_cast
并不进行用以确保该对象的运行时类型确实是D
的运行时检查,而且仅当这项前提条件由其他方法所保证时才能安全使用,例如在实现静多态时。可以用dynamic_cast
执行安全的向下转型。1
2
3
4
5struct B { };
struct D : B { };
D d;
B& br = d;
static_cast<D&>(br); // 左值指代原初的 d 对象(本条自C++11起) 若 new_type 是右值引用类型,则
static_cast
将泛左值、类纯右值或数组纯右值 (C++17 前) 任何左值 (C++17 起) expression 的值转换为与该表达式指代相同对象,或指代其基类子对象(取决于 new_type)的亡值。若目标类型是表达式的不可访问或有歧义基类,则程序非良构。若表达式是位域左值,则它首先被转换成底层类型的纯右值。这种static_cast
用于在std::move
中实现移动语义。若 new_type 是(可为 cv 限定的)void 类型,则
static_cast
在求值 expression 后舍弃其值。若存在从 new_type 到 expression 类型的标准转换序列,且它不包含左值到右值、数组到指针、函数到指针、空指针、空成员指针、函数指针 (C++17 起)或布尔转换,则
static_cast
能进行该隐式转换的逆转换。若从 expression 到 new_type 涉及左值到右值、数组到指针或函数到指针转换,则能显式用
static_cast
进行。有作用域枚举类型(C++11)能转换成整数或浮点类型。
- 当目标类型为 cv bool 时,若原值为零则结果为 false,而对所有其他值结果为 true。对于其余整型类型,若该枚举的值能以目标类型表示,则结果为其值,否则结果未指明。(C++20前)
- 其结果与从枚举的底层类型隐式转换成目标类型的结果相同。 (C++20 起)
整数或枚举类型值可转换为任何完整枚举类型。
指向某类
D
的成员的指针可以向上转型(upcast)为指向其无歧义、可访问的基类B
的成员。这种static_cast
不进行用以确保成员实际存在于所指向对象的运行时类型的检查。指向(可有 cv 限定)void 的指针类型的纯右值可转换到指向任何对象的指针类型。若原指针值所表示的内存中字节地址不满足目标类型的对齐要求,则结果指针值未指明。否则,若原指针值指向对象 a,且存在与 a 指针可互转换(定义于下文)的目标类型的(忽略 cv 限定)对象 *b,则结果为指向 *b 的指针。否则指针值不改变。任何指针转换到 void 指针,再转换回原(或更为 cv 限定的)类型的指针,都保持其原值。
同所有转型表达式,结果是:
- 左值,若 new_type 是左值引用或到函数类型的右值引用;
- 亡值,若 new_type 是到对象类型的右值引用;
- 否则为纯右值。
满足以下条件时,两个对象 a 与 b 指针可互转换(pointer-interconvertible):
- 它们为同一对象,或
- 一个是 union 对象而另一个是该对象的非静态数据成员,或
- 一个是标准布局类对象,而另一个是该对象的首个非静态数据成员,或若该对象无非静态数据成员,则为该对象的任何基类子对象,或
- 存在对象 c 使得 a 与 c 指针可互转换,而 c 与 b 指针可互转换。
1 | union U { int a; double b; } u; |
注
static_cast
亦可用于通过进行到指定类型的函数到指针转换,来消解函数重载的歧义。如
1 | std::for_each(files.begin(), files.end(), |
dynamic_cast
沿继承层级向上、向下及侧向,安全地转换到其他类的指针和引用。
语法
dynamic_cast <new_type> (expression)
new_type:指向完整类类型的指针、到完整类类型的引用,或指向(可选的 cv 限定)void 的指针
expression*:若 *new_type 为引用,则为完整类类型的 左值 (C++11 前) / 泛左值 (C++11 起) 表达式,若 new_type 为指针,则为指向完整类类型的指针纯右值。
若转型成功,则 dynamic_cast
返回 new_type 类型的值。若转型失败且 new_type 是指针类型,则它返回该类型的空指针。若转型失败且 new_type 是引用类型,则它抛出与类型 std::bad_cast 的处理块匹配的异常。
解释
唯有下列转换能用 dynamic_cast
进行,但若这种转换会转换走常量性或易变性则亦不允许。
若 expression 的类型恰是 new_type 或 new_type 的较少 cv 限定版本,则结果是 expression 具有 new_type 类型的值。(换言之,dynamic_cast 可用以添加常量性。隐式转换和 static_cast 亦能进行此转换。)
若 expression 的值是空指针值,则结果是 new_type 类型的空指针值。
若 new_type 是到
Base
的指针或引用,且 expression 的类型是到Derived
的指针或引用,其中Base
是Derived
的唯一可访问基类,则结果是到 expression 所标识的对象中Base
类子对象的指针或引用。(注意:隐式转换和 static_cast 亦能进行此转换。)若 expression 是指向多态类型的指针,且 new_type 是到 void 的指针,则结果是指向 expression 所指向或引用的最终派生对象的指针。
多态对象:声明或继承了至少一个虚函数的类类型的对象是多态对象
若 expression 是到多态类型
Base
的指针或引用,且 new_type 是到Derived
类型的指针或引用,则进行运行时检查:a) 检验 expression 所指向/标识的最终派生对象。若在该对象中 expression 指向/指代
Derived
的公开基类,且只有一个Derived
类型对象从 expression 所指向/标识的子对象派生,则转型结果指向/指代该Derived
对象。(此之谓“向下转型(downcast)”。)b) 否则,若 expression 指向/指代最终派生对象的公开基类,而同时最终派生对象拥有
Derived
类型的无歧义公开基类,则转型结果指向/指代该Derived
(此之谓“侧向转型(sidecast)”。)c) 否则,运行时检查失败。若 dynamic_cast 用于指针,则返回 new_type 类型的空指针值。若它用于引用,则抛出 std::bad_cast 异常。
当在构造函数或析构函数中(直接或间接)使用 dynamic_cast,且 expression 指代正在构造/销毁的对象时,该对象被认为是最终派生对象。若 new_type 不是到构造函数/析构函数自身的类或其基类之一的指针或引用,则行为未定义。
与其他转型表达式相似:
- 若 new_type 是左值引用类型(expression 必为左值),则其结果为左值
- 若 new_type 是右值引用类型(expression 为完整类类型,可以是左值或右值 (C++17 前) / 必为泛左值(纯右值被实质化) (C++17 起)),则其结果为亡值
- 若 new_type 是指针类型,则其结果为纯右值
注
- 亦可用 static_cast 进行向下转型,它避免运行时检查的开销,但只有在程序(通过某些其他逻辑)能够保证 表达式 所指向的对象肯定是
Derived
时才是安全的。 - 某些形式的 dynamic_cast 依赖于运行时类型鉴别( RTTI ),即编译的程序中关于每个多态类的信息。编译器通常有选项禁用此信息。
测试代码
1 |
|
const_cast
在有不同 cv 限定的类型间转换。
语法
const_cast <new_type> (expression)
返回 new_type 类型的值。
解释
唯有下列转换能用 const_cast
进行。特别是,唯有 const_cast
可用于转型掉(移除)常量性或易变性。
两个指向同一类型的可能多级的指针可以互相转换,无关乎每个层级的 cv 限定符。
任何
T
类型的左值可转换为到同一类型T
的左值或右值引用,cv 限定可更多或更少。同样地,类类型纯右值或任何类型的亡值可转换成具有更多或更少 cv 限定的右值引用。引用const_cast
的结果指代原对象,若 expression 是泛左值,否则指代实质化的临时量 (C++17 起)。同样的规则适用于可能多层的到数据成员的指针,及可能多层的到已知和未知边界数组(cv 限定元素的数组被认为是自身亦有 cv 限定) (C++17 起)
空指针值可转换成 new_type 的空指针值
同所有转型表达式,结果是:
- 左值,若 new_type 是左值引用或到函数类型的右值引用;
- 亡值,若 new_type 是到对象类型的右值引用;
- 否则为纯右值。
注
函数指针和成员函数指针不可用于 const_cast
。
const_cast
使得能够组成实际指代 const 对象 的到非 const 类型的引用或指针,或组成实际指代 volatile 对象的到非 volatile 类型的引用或指针。通过非 const 访问路径修改 const 对象和通过非 volatile 泛左值涉指 volatile 对象是未定义行为。
测试代码
1 |
|
reinterpret_cast
通过重新解释底层位模式在类型间转换。
语法
reinterpret_cast <new_type> (expression)
返回 new_type
类型的值。
解释
与 static_cast
不同,但与 const_cast
类似,reinterpret_cast
表达式不会编译成任何 CPU 指令(除非在整数和指针间转换,或在指针表示依赖其类型的不明架构上)。它纯粹是一个编译时指令,指示编译器将 expression 视为如同具有 new_type 类型一样处理。
唯有下列转换能用 reinterpret_cast
进行,但若转换会转型走常量性或易变性则亦不允许。
整型、枚举、指针或成员指针类型的表达式可转换到其自身的类型。产生的值与 表达式 的相同。(C++11 起)
指针能转换成大小足以保有其类型所有值的任何整型类型(例如转换成
std::uintptr_t
)任何整型或枚举类型的值可转换到指针类型。指针转换到有足够大小的整数再转换回同一指针类型后,保证拥有其原值,否则结果指针无法安全地解引用(不保证相反方向的往返转换;相同指针可拥有多种整数表示)。不保证空指针常量
NULL
或整数零生成目标类型的空指针值;为此目的应该用static_cast
或 隐式转换。任何
std::nullptr_t
类型的值,包括nullptr
,可转换成任何整型类型,如同它是(void*)0
一样,但没有值能转换成std::nullptr_t
,甚至nullptr
也不行:为该目的应该用static_cast
。(C++11 起)任何对象指针类型
T1*
可转换成指向对象指针类型cv T2
。这严格等价于static_cast<cv T2*>(static_cast<cv void*>(表达式))
(这意味着,若T2
的对齐要求不比T1
的更严格,则指针值不改变,且将结果指针转换回原类型将生成其原值)。任何情况下,只有类型别名化(type aliasing)规则(见此)允许时,结果指针才可以安全地解引用。T1
类型的左值表达式可转换成到另一个类型T2
的引用。结果是与原左值指代同一对象,但有不同类型的左值或亡值。不创建临时量,不进行复制,不调用构造函数或转换函数。只有类型别名化(type aliasing)规则(见此)允许时,结果指针才可以安全地解引用。任何函数指针可转换成指向不同函数类型的指针。通过指向不同函数类型的指针调用函数是未定义的,但将这种指针转换回指向原函数类型的指针将生成指向原函数的指针值。
一些实现上(特别是在任何 POSIX 兼容的系统上,即基于 dlsym 的要求),函数指针可以转换成 void* 或任何其他对象指针,反之亦然。若实现支持双向的转换,则转换回原类型将生成原值,否则结果指针不能安全地解引用或调用。
任何指针类型的空指针值可转换成任何其他指针类型,产生该类型的空指针值。注意不能用
reinterpret_cast
将空指针常量nullptr
或任何其他std::nullptr_t
类型的值转换为指针:为此目的应该使用隐式转换或static_cast
。成员函数指针可转换成指向不同类型的不同成员函数的指针。转换回原类型将生成原值,否则结果指针不能安全使用。
指向某类
T1
的成员对象的指针可转换成指向另一个类T2
的另一个成员对象的指针。若T2
的对齐不比T1
更严格,则转换回原类型T1
将生成原值,否则不能安全地使用结果指针。
同所有转型表达式,结果是:
- 左值,若 new_type 是左值引用或到函数类型的右值引用;
- 亡值,若 new_type 是到对象类型的右值引用;
- 否则为纯右值。