命名空间
变体
操作

static_cast 转换

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句 (循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (在 C++17* 中已弃用)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

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

内容

[编辑] 语法

static_cast<target-type >(expression )

返回 target-type 类型的值。

[编辑] 解释

只有以下转换可以使用 static_cast 完成,除非此类转换会移除 constness(或 volatility)。

1) 如果 expression 是 “cv1 Base” 类型的左值,并且 target-type 是 “cv2 Derived 的引用”,则如果满足以下所有条件,则结果引用类型为 Derived 的对象,该对象包含 expression
  • Derived 是一个完整的类类型。
  • BaseDerived 的基类。
  • cv1 不是比 cv2 更强的 cv 限定符。
如果满足以下任何条件,则程序是非良构的
  • BaseDerived虚基类
  • BaseDerived 的虚基类的基类。
  • 不存在从 “指向 Derived 的指针” 到 “指向 Base 的指针” 的有效标准转换
如果 expression 实际上不是 Derived 类型对象的基类子对象,则行为未定义。
struct B {};
struct D : B { B b; };
 
D d;
B& br1 = d;
B& br2 = d.b;
 
static_cast<D&>(br1); // OK, lvalue denoting the original “d” object
static_cast<D&>(br2); // UB: the “b” subobject is not a base class subobject
2) 如果 target-type 是 “Derived 的右值引用”,并且 expression 是 “(可能带有 cv 限定符的) Base” 类型的 xvalue,使得 BaseDerived 的基类,则此类转换的结果和约束与 “Base 左值到 Derived 引用的” 转换相同。
3) 如果 target-type 是右值引用类型,并且被引用的类型与 expression 的类型引用兼容,则 static_castglvalue、类 prvalue 或数组 prvalue(C++17 前)任何左值(C++17 起) expression 的值转换为引用与表达式相同的对象或其基类子对象(取决于 target-type)的 xvalue。[1]
如果 target-typeexpression 类型的不可访问或不明确的基类,则程序是非良构的。
如果 expression位域左值,则首先将其转换为底层类型的 prvalue。
(C++11 起)
4) 如果 target-type 是(可能带有 cv 限定符的)void,则转换没有结果。在这种情况下,expression 是一个弃值表达式
5) 否则,如果满足以下条件,则可以将 expression 显式转换为 target-type

声明 target-type temp(expression ); 对于某些发明的临时变量 temp 是良构的。

这种显式转换的效果与执行声明和初始化,然后使用 temp 作为转换结果的效果相同。expression  被用作 一个左值(C++11 前)一个 glvalue(C++11 起) 当且仅当初始化将其用作 一个左值(C++11 前)一个 glvalue(C++11 起)

(C++17 前)

满足以下任何条件

  • 存在从 expressiontarget-type 的隐式转换序列。
  • expression 直接初始化类型为 target-type 的对象或引用的重载解析将找到至少一个可行的函数。
  • target-type 是一个聚合类型,其具有第一个元素 x,并且存在从 expressionx 类型的隐式转换序列。
(C++20 起)

显式转换定义如下

  • 如果 target-type 是引用类型,则效果与执行声明和初始化 target-type temp(expression ); 对于某些发明的临时变量 temp,然后使用 temp 作为转换结果的效果相同。
  • 否则,结果对象将从 expression  直接初始化。
(C++17 起)
6) 否则,如果从 expressiontarget-type 的转换是标准转换序列的逆过程,并且该转换序列不包含以下任何转换,则可以使用 static_cast 执行转换
(C++17 起)
如果程序使用 static_cast 执行非良构的标准转换序列的逆过程,则它是非良构的。
7) 否则,左值到右值、数组到指针和函数到指针的转换将应用于 expression。在这些转换之后,只有以下转换可以使用 static_cast 执行
a) 作用域枚举类型的值可以转换为整数或浮点类型。
  • 如果 target-type 是(可能带有 cv 限定符的)bool,则如果 expression 的原始值为零,则结果为 false,对于所有其他值,结果为 true
  • 如果 target-type 是除(可能带有 cv 限定符的)bool 之外的整数类型,则如果 expression 的原始值可以由 target-type 表示,则该值不变。否则,结果值是未指定的。
(C++20 前)
  • 如果 target-type 是整数类型,则结果与转换为枚举的底层类型,然后再转换为 target-type 的结果相同。
(C++20 起)
  • 如果 target-type 是浮点类型,则结果与从原始值转换为 target-type 的结果相同。
(C++11 起)
b) 整数或枚举类型的值可以转换为任何完整的枚举类型。
  • 如果 target-type 具有固定的底层类型,则 expression 首先通过整型提升整型转换(如果必要)转换为该类型,然后再转换为 target-type
  • 如果 target-type 没有固定的底层类型,则如果原始值在枚举值的范围内,则 expression 的值不变,否则行为未定义。
c) 浮点类型的值也可以转换为任何完整的枚举类型。结果与首先将 expression 的原始值转换target-type 的底层类型,然后再转换为 target-type 本身的结果相同。
d) 浮点类型的 prvalue 可以显式转换为任何其他浮点类型。
  • 如果 expression 的源值可以在 target-type 中精确表示,则它不会更改。
  • 否则,如果 expression 的源值在 target-type 的两个可表示值之间,则转换的结果是这两个值中实现定义的选择。[2]
  • 否则,行为未定义。
(C++23 起)
e) “指向 cv1 Base 的指针” 类型的右值(C++11 前)prvalue(C++11 起)可以显式转换为 “指向 cv2 Derived 的指针” 类型,如果满足以下所有条件
  • Derived 是一个完整的类类型。
  • BaseDerived 的基类。
  • cv1 不是比 cv2 更强的 cv 限定符。
如果 expression空指针值,则结果是 target-type 类型的空指针值。否则,结果是指向类型为 Derived 的对象的指针,该对象包含 expression 指向的类型为 Base 的对象。
如果满足以下任何条件,则程序是非良构的
  • BaseDerived虚基类
  • BaseDerived 的虚基类的基类。
  • 不存在从 “指向 Derived 的指针” 到 “指向 Base 的指针” 的有效标准转换。
如果 expression 不是空指针值,并且实际上并未指向类型为 Derived 的对象的基类子对象,则行为未定义。
f) “指向 Derived 的成员,类型为 cv1 T” 类型的右值(C++11 前)prvalue(C++11 起)可以显式转换为 “指向 Base 的成员,类型为 cv2 T” 类型,如果满足以下所有条件
  • Derived 是一个完整的类类型。
  • BaseDerived 的基类。
  • cv1 不是比 cv2 更强的 cv 限定符。
如果 expression 是空成员指针值,则结果是 target-type 类型的空成员指针值。否则,结果是指向类 Base 的原始(可能间接)成员的指针。
如果不存在从 “指向 Base 的成员,类型为 T” 到 “指向 Derived 的成员,类型为 T” 的有效标准转换,则程序是非良构的。
如果 expression 不是空成员指针值,并且它表示的成员不是类 Base 的(可能间接)成员,则行为未定义。
g) “指向 cv1 void 的指针” 类型的右值(C++11 前)prvalue(C++11 起)可以显式转换为 “指向 cv2 T 的指针” 类型,如果 T 是对象类型且 cv1 不是比 cv2 更强的 cv 限定符。
  • 如果 expression 是空指针值,则结果是 target-type 类型的空指针值。
  • 如果 expression 表示内存中字节的地址 A,并且 A 满足 T对齐要求,则生成的指针值也表示 A
  • 任何其他此类指针转换的结果都是未指定的。
  • 如果 expression 是先前从 “指向 cv3 T 的指针” 类型的对象转换的结果,则结果具有原始值。
(C++17 前)
  • 如果 expression 表示内存中字节的地址 A,但 A 不满足 T对齐要求,则生成的指针值是未指定的。
  • 否则,如果 expression 指向对象 a,并且存在一个与 a 指针可互转换(见下文)的类型为 T(忽略 cv 限定符)的对象 b,则结果是指向 b 的指针。
  • 否则,指针值在转换中保持不变。
(C++17 起)

与所有强制转换表达式一样,结果是

  • 如果 target-type 是左值引用类型或函数类型的右值引用(C++11 起),则为左值;
  • 如果 target-type 是对象类型的右值引用,则为 xvalue;
(C++11 起)
  • 否则为 prvalue。
  1. static_cast 用于在 std::move 中实现移动语义。
  2. [编辑] 指针可互转换对象

    如果满足以下条件,则两个对象 ab指针可互转换的

    • 它们是同一个对象,或者
    • 一个是联合体对象,另一个是该对象的非静态数据成员,或者
    • 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员或该对象的任何基类子对象,或者
    • 存在一个对象 c,使得 ac 是指针可互转换的,并且 cb 是指针可互转换的。
    union U { int a; double b; } u;
    void* x = &u;                        // x's value is “pointer to u”
    double* y = static_cast<double*>(x); // y's value is “pointer to u.b”
    char* z = static_cast<char*>(x);     // z's value is “pointer to u”

    [编辑] 注释

    使用 static_cast 的基类到派生类的转换(向下转型)不进行运行时检查以确保指向/引用的对象的动态类型Derived,并且只有在其他方式保证此先决条件的情况下才能安全使用,例如在实现静态多态时。可以使用dynamic_cast 进行安全向下转型。

    static_cast 也可以用于通过执行到特定类型的函数到指针的转换来消除函数重载的歧义,例如

    std::for_each(files.begin(), files.end(),
                  static_cast<std::ostream&(*)(std::ostream&)>(std::flush));

    [编辑] 关键字

    static_cast

    [编辑] 示例

    #include <iostream>
    #include <vector>
     
    struct B
    {
        int m = 42;
        const char* hello() const
        {
            return "Hello world, this is B!\n";
        }
    };
     
    struct D : B
    {
        const char* hello() const
        {
            return "Hello world, this is D!\n";
        }
    };
     
    enum class E { ONE = 1, TWO, THREE };
    enum EU { ONE = 1, TWO, THREE };
     
    int main()
    {
        // 1. static downcast
        D d;
        B& br = d; // upcast via implicit conversion
        std::cout << "1) " << br.hello();
        D& another_d = static_cast<D&>(br); // downcast
        std::cout << "1) " << another_d.hello();
     
        // 3. lvalue to xvalue
        std::vector<int> v0{1, 2, 3};
        std::vector<int> v2 = static_cast<std::vector<int>&&>(v0);
        std::cout << "3) after move, v0.size() = " << v0.size() << '\n';
     
        // 4. discarded-value expression
        static_cast<void>(v2.size());
     
        // 5. initializing conversion
        int n = static_cast<int>(3.14);
        std::cout << "5) n = " << n << '\n';
        std::vector<int> v = static_cast<std::vector<int>>(10);
        std::cout << "5) v.size() = " << v.size() << '\n';
     
        // 6. inverse of implicit conversion
        void* nv = &n;
        int* ni = static_cast<int*>(nv);
        std::cout << "6) *ni = " << *ni << '\n';
     
        // 7a. scoped enum to int
        E e = E::TWO;
        int two = static_cast<int>(e);
        std::cout << "7a) " << two << '\n';
     
        // 7b. int to enum, enum to another enum
        E e2 = static_cast<E>(two);
        [[maybe_unused]]
        EU eu = static_cast<EU>(e2);
     
        // 7f. pointer to member upcast
        int D::*pm = &D::m;
        std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n';
     
        // 7g. void* to any object pointer
        void* voidp = &e;
        [[maybe_unused]]
        std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
    }

    输出

    1) Hello world, this is B!
    1) Hello world, this is D!
    3) after move, v0.size() = 0
    5) n = 3
    5) v.size() = 10
    6) *ni = 3
    7a) 2
    7f) 42

    [编辑] 缺陷报告

    以下行为更改缺陷报告被追溯应用于先前发布的 C++ 标准。

    DR 应用于 已发布行为 正确行为
    CWG 137 C++98 的 constness 和 volatility
    指向 void 的指针可以被移除 constness
    cv 限定符不能在
    这种情况下被移除
    CWG 427 C++98 向下转型可能与直接初始化不明确 在这种情况下选择向下转型
    CWG 439 C++98 当将 “指向对象的指针” 转换为 “指向
    void” 然后转换回自身时,只有当
    结果类型具有相同的 cv 限定符时,它才能保留其值
    cv 限定符
    可能不同
    CWG 1094 C++98 从浮点值转换
    为枚举值是未指定的
    已指定
    CWG 1320 C++11 从作用域枚举转换
    值为 bool 是未指定的
    已指定
    CWG 1412 C++98 从转换的结果
    “指向
    void” 到 “指向对象” 是不明确的
    已明确
    CWG 1447 C++11 从位域转换为右值引用
    是未指定的(无法将引用绑定到位域)
    已指定
    CWG 1766 C++98 从整数或枚举值转换为枚举
    如果 expression 超出范围,则值会产生未指定的结果
    行为是
    在这种情况下未定义
    CWG 1832 C++98 从整数或枚举值转换为
    枚举值允许 target-type 为不完整类型
    不允许
    CWG 2224 C++98 从基类类型成员转换为
    其派生类类型的完整对象是有效的
    行为是
    在这种情况下未定义
    CWG 2254 C++11 没有数据成员的标准布局类对象
    与其第一个基类是指针可互转换的
    它是指针可互转换的
    与其任何基类
    CWG 2284 C++11 非标准布局联合体对象和非静态数据
    该对象的成员不是指针可互转换的
    它们是
    CWG 2310 C++98 对于基类到派生类指针转换和
    派生类到基类成员指针转换,
    派生类类型可能是不完整的
    必须是完整的
    CWG 2338 C++11 转换为具有固定底层类型的枚举类型
    如果 expression 超出范围,则会导致未定义的行为
    转换为底层类型
    首先(没有未定义的行为)
    CWG 2499 C++11 标准布局类可能具有不可指针互转换的
    基类,即使所有基类子对象都具有相同的地址
    它没有
    CWG 2718 C++98 对于基类到派生类引用转换,
    派生类类型可能是不完整的
    必须是完整的
    CWG 2882 C++98 不清楚 static_cast<void>(expr) 尝试
    exprvoid 形成隐式转换序列
    在这种情况下不尝试

    [编辑] 参考资料

    • C++23 标准 (ISO/IEC 14882:2024)
    • 7.6.1.9 Static cast [expr.static.cast]
    • C++20 标准 (ISO/IEC 14882:2020)
    • 7.6.1.8 Static cast [expr.static.cast]
    • C++17 标准 (ISO/IEC 14882:2017)
    • 8.2.9 静态转换 [expr.static.cast]
    • C++14 标准 (ISO/IEC 14882:2014)
    • 5.2.9 静态转换 [expr.static.cast]
    • C++11 标准 (ISO/IEC 14882:2011)
    • 5.2.9 静态转换 [expr.static.cast]
    • C++98 标准 (ISO/IEC 14882:1998)
    • 5.2.9 静态转换 [expr.static.cast]
    • C++03 标准 (ISO/IEC 14882:2003)
    • 5.2.9 静态转换 [expr.static.cast]

    [编辑] 参见