static_cast 转换

来自cppreference.com
< cpp‎ | language
 
 
 
表达式
概述
值类别(左值 lvalue 、右值 rvalue 、亡值 xvalue )
求值顺序(序列点)
常量表达式
不求值表达式
初等表达式
lambda 表达式(C++11)
字面量
整数字面量
浮点字面量
布尔字面量
字符字面量,包含转义序列
字符串字面量
空指针字面量(C++11)
用户定义字面量(C++11)
运算符
赋值运算符a=b, a+=b, a-=b, a*=b, a/=b, a%=b, a&=b, a|=b, a^=b, a<<=b, a>>=b
自增与自减++a, --a, a++, a--
算术运算符+a, -a, a+b, a-b, a*b, a/b, a%b, ~a, a&b, a|b, a^b, a<<b, a>>b
逻辑运算符a||b, a&&b, !a
比较运算符a==b, a!=b, a<b, a>b, a<=b, a>=b, a<=>b(C++20)
成员访问运算符a[b], *a, &a, a->b, a.b, a->*b, a.*b
其他运算符a(...), a,b, a?b:c
运算符的替代表示
优先级和结合性
折叠表达式(C++17)
new 表达式
delete 表达式
throw 表达式
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
运算符重载
类型转换
隐式转换
const_cast
static_cast
reinterpret_cast
dynamic_cast
显式转换 (T)a, T(a)
用户定义转换
 

用隐式和用户定义转换的组合在类型间转换。

目录

[编辑] 语法

static_cast < new_type > ( expression )

返回 new_type 类型的值。

[编辑] 解释

唯有下列转换能用 static_cast 执行,除了这种转换会转型走常性易变性的情况。

1) 若有从 expressionnew_type隐式转换序列,或若new_type 类型对象或引用的自 expression直接初始化会找到至少一个可生成函数,则 static_cast<new_type>(expression) 返回如同以 new_type Temp(expression); 初始化的虚构变量 Temp ,它可能涉及隐式转换、对 new_type 构造函数的调用或对用户定义转换运算符的调用。对于非引用的 new_type , static_cast 纯右值表达式的结果对象是被直接初始化者 (C++17 起)
2)new_type 是到某类类型 D 的指针或引用,且 expression 的类型是到其非虚基类 B 的指针或引用,则 static_cast 进行向下转型。若 BD 的歧义、不可访问或虚基类(或虚基类的基类),则此向下转型病态。这种 static_cast 不进行运行时检查以确保该对象的运行时类型确实是 D ,而且仅若此前提条件为其他方法所保证才能安全使用,例如在实现静多态时。安全的向下转型可以用 dynamic_cast 执行。
3)new_type 是右值引用类型,则 static_cast 转换泛左值、类纯右值或数组纯右值 (C++17 前)任何左值 (C++17 起) expression 的值为与该表达式指代相同对象,或指代其基类子对象(取决于 new_type )的亡值。若目标类型是表达式的不可访问或有歧义基类,则程序为病态。若表达式是位域左值,则它首先被转换成底层类型的纯右值。此类型的 static_cast 用于在 std::move 中实现移动语义。
(C++11 起)
4)new_typevoid 类型(可为 cv 限定),则 static_cast 在求值 expression 后舍弃其值。
5) 若存在从 new_typeexpression 类型的标准转换序列,且它不包含左值到右值、数组到指针、函数到指针、空指针、空成员指针、函数指针 (C++17 起)或布尔转换,则 static_cast 能进行该隐式转换的逆转换。
6) 若从 expressionnew_type 设计左值到右值、数组到指针或函数到指针转换,则它能显式以 static_cast 进行。
7) 有作用域枚举类型能转换成整数或浮点类型。当目标类型是 cv bool 时,若原值为零则结果为 false ,而对所有其他值结果为 true 。对于其余整数类型,若它们表示为目标类型,则结果是枚举的值,否则结果未指定。(C++11 起)
8) 整数或枚举类型值能转换为任何完整枚举类型
  • 若底层类型不固定,则若 expression 的值落在范围(范围是大到足以保有目标枚举的所有枚举项的最小位域的所有可能值)外则结果未指定 (C++17 前)为未定义行为 (C++17 起)
  • 若底层类型固定,则结果同转换原值到枚举的底层类型再到该枚举类型的结果。
9) 指向某类 D 成员的指针能向上转型为指向其无歧义、可访问的基类 B 。此 static_cast 不进行检查以确保成员实际存在于所指向对象的运行时类型。
10) 指向(可有 cv 限定) void 指针类型的纯右值能转换到指向任何对象指针类型。若原指针值所表示的内存中字节地址不满足目标类型对齐要求,则结果指针值未指定。否则,若原指针值指向对象 a ,而有与 a 指针可互转换(定义于下)的目标类型(忽略 cv 限定)对象 b ,则结果为指向 b 的指针。否则指针值不改变。任何指针转换到指向 void 指针,再转换回指向原(或更为 cv 限定的)类型的指针,都保持其原值。

同所有转型表达式,结果是:

  • 左值,若 new_type 是左值引用或到函数类型的右值引用;
  • 亡值,若 new_type 是到对象类型的右值引用;
  • 否则为纯右值。

二个对象 ab 指针可互转换,若:

  • 它们为同一对象,或
  • 一个是 union 对象而另一个是该对象的非静态数据成员,或
  • 一个是标准布局类对象,而另一个是该对象的首个非静态数据成员,或若该对象无非静态数据成员,则为该对象的首个基类子对象,或
  • 存在对象 c 使得 ac 指针可互转换,而 cb 指针可互转换。
union U { int a; double b; } u;
void* x = &u;                        // x 的值为“指向 u 的指针”
double* y = static_cast<double*>(x); // y 的值为“指向 u.b 的指针”
char* z = static_cast<char*>(x);     // z 的值为“指向 u 的指针”

[编辑] 注意

static_cast 亦可用于消歧义函数重载,通过进行到指定类型的函数到指针转换,如于 std::transform(s.begin(), s.end(), s.begin(), static_cast<int(*)(int)>(std::toupper));

[编辑] 关键词

static_cast

[编辑] 示例

#include <vector>
#include <iostream>
 
struct B {
    int m = 0;
    void hello() const {
        std::cout << "Hello world, this is B!\n";
    }
};
struct D : B {
    void hello() const {
        std::cout << "Hello world, this is D!\n";
    }
};
 
enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };
 
int main()
{
    // 1: 初始化转换
    int n = static_cast<int>(3.14); 
    std::cout << "n = " << n << '\n';
    std::vector<int> v = static_cast<std::vector<int>>(10);
    std::cout << "v.size() = " << v.size() << '\n';
 
    // 2: 静态向下转型
    D d;
    B& br = d; // 通过隐式转换向上转型
    br.hello();
    D& another_d = static_cast<D&>(br); // 向下转型
    another_d.hello();
 
    // 3: 左值到亡值
    std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
    std::cout << "after move, v.size() = " << v.size() << '\n';
 
    // 4: 弃值表达式
    static_cast<void>(v2.size());
 
    // 5. 隐式转换的逆
    void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "*ni = " << *ni << '\n';
 
    // 6. 数组到指针后随向上转型
    D a[10];
    B* dp = static_cast<B*>(a);
 
    // 7. 有作用域枚举到 int 或 float
    E e = E::ONE;
    int one = static_cast<int>(e);
    std::cout << one << '\n';
 
    // 8. int 到枚举,枚举到另一枚举
    E e2 = static_cast<E>(one);
    EU eu = static_cast<EU>(e2);
 
    // 9. 指向成员指针向上转型
    int D::*pm = &D::m;
    std::cout << br.*static_cast<int B::*>(pm) << '\n';
 
    // 10. void* 到任何类型
    void* voidp = &e;
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}

输出:

n = 3
v.size() = 10
Hello world, this is B!
Hello world, this is D!
after move, v.size() = 0
*ni = 3
1
0

[编辑] 参阅