[C/C++]_[中级]_[static_cast的详细解析]

Posted infoworld

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C/C++]_[中级]_[static_cast的详细解析]相关的知识,希望对你有一定的参考价值。

场景

  1. C++开发时,会看到四个强制类型转换操作符const_cast,dynamic_cast,static_castreinterpret_cast。其中static_cast的用在什么场景下?

说明

  1. static_cast是不安全的转换,不会对类型进行检查。只在一种情况下进行简单检查,即没有继承关系的对象不能转,编译报错。通常用在把指向基类的指针转换为指向子类的指针;可以用在数值类型int,char,enum,float,double等之间的转换;一般用在非多态(无virtual)的类型转换中。
static_cast <type-id> ( expression )

基类向下转换

  1. type-id可以是引用类型,指针类型。
D& d2 = static_cast<D&>(b2);
D* d2_3 = dynamic_cast<D*>(&b2);

  1. 对实际类型是父类型的对象转换为子类型,可以转,但是调用时结果是未定义的。也就可能运行时报错,也可能不报错。dynamc_cast动态转换失败会返回0,而0初始化一个引用类型D&会崩溃, 如果是转换为dynamic_cast<D*>就不会报错。
B b2;
D& d2 = static_cast<D&>(b2);

//因为dynamc_cast动态转换失败会返回0,而0初始化一个引用类型D&会崩溃。
//D& d2_2 = dynamic_cast<D&>(b2);

左值(lvalue)转换为过期值(xvalue)

  1. 左值lvalue转换为过期值xvalue,items已经失效,size0.有时候需要某些元素添加更长的生命周期,转换为xvalue是最小的代价。
vector<int> items = 1,2,3;
vector<int>* items2 = new vector<int>(static_cast<vector<int>&&>(items));

数值类型的转换

  1. 用法作用和C(T)强制类型转换一样,不会对结果进行检查,这里涉及到大小字节之间转换的正确性需要程序员自己考虑。
char ch1 = 'a';
int i = static_cast<int>(100.04);
ch1 = static_cast<char>(i);

基类指向子类的成员变量或函数

  1. 这类方法一般会用在回调时,使用父类调用子类的函数,调用的是子类的函数。注意实际的对象要是对应的子类才行。
typedef void (C::*FuncHello)();
auto E::*f2 = &E::hello;
(c.*static_cast<FuncHello>(f2))();

typedef void (B::*VirtualFuncHello)();
auto D::*f3 = &D::hello;
(b.*static_cast<VirtualFuncHello>(f3))();

例子

// test-static-cast.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <vector>
#include <string>
#include <assert.h>

using namespace std;

struct A 

    A()  cout << "A" << endl; 
    int a = 1;
    void hello()  cout << "A hello" << endl; 
;

struct B : A

    B()  cout << "B" << endl; 
    int b = 2;
    virtual void hello()  cout << "B hello" << endl; 
;

struct C : A

    C()  cout << "C" << endl; 
    int c = 3;
    void hello()  cout << "C hello" << endl; 
;

struct D : B

    D()  cout << "D" << endl; 
    int d = 4;
    void world()  cout << "D world" << endl; 
    void hello()  cout << "D hello" << endl; 
;

struct E : C

    E()  cout << "E" << endl; 
    int e = 5;
    void world()  cout << "E world" << endl; 
    void hello()  cout << "E hello" << endl; 
;

int main()

    std::cout << "Hello World!\\n";

    // b virtual 
    cout << " ===== 1 ===== " << endl;
    D d;
    B& b = d;
    b.hello();

    B* b1 = &d;
    b1->hello();

    // e not virtual
    cout << " ===== 2 ===== " << endl;
    E e;
    C& c = e;
    c.hello();

    C* c1 = &e;
    c1->hello();

    // 编译错误: 类型转换无效。类类型B和C没有关系。
    // C& c2 = static_cast<C&>(b);

    // 向下转换, 因为 D 是多态的子类,实际指向的对象还是 D.
    cout << " ===== 3 ===== " << endl;
    D& d1 = static_cast<D&>(b);
    d1.hello();

    // 向下转换非多态继承,实际对象是E,所以转换成功。转换为E对象。
    cout << " ===== 4 ===== " << endl;
    E& e1 = static_cast<E&>(c);
    e1.hello(); 

    // A并不是虚父类,构不成多态关系。所以对象指向 a.
    cout << " ===== 5 ===== " << endl;
    A& a = b;
    a.hello();

    A& a1 = d;
    a.hello();

    // 向下转换,不安全的做法,编译器不会检查,打印的实际对象是B. 注意如果调用在B不存在,在D里存在的方法可能会崩溃,未定义行为。
    
    cout << " ===== 6 ===== " << endl;
    B b2;
    D& d2 = static_cast<D&>(b2);

    //因为dynamc_cast动态转换失败会返回0,而0初始化一个引用类型D&会崩溃。
    //D& d2_2 = dynamic_cast<D&>(b2);

    D* d2_3 = dynamic_cast<D*>(&b2);
    assert(d2_3 == NULL);

    C c2_1;
    // 不是多态类型,编译报错。
    //E* e2_1 = dynamic_cast<E*>(&c2_1);

    //以下调用可能会崩溃。
    //d2.hello();
    //以下调用可能会崩溃。
    //d2.world();

    cout << " ===== 7 ===== " << endl;
    C c2;
    E& e2 = static_cast<E&>(c2);
    //以下调用可能会崩溃。
    //e2.hello();

    // 左值 lvalue 转换为过期值 xvalue,items已经失效,size是0.
    // 有时候需要某些元素添加更长的生命周期,转换为xvalue是最小的代价。
    cout << " ===== 8 ===== " << endl;
    vector<int> items = 1,2,3;
    cout << "items.size(): " << items.size() << endl;
    vector<int>* items2 = new vector<int>(static_cast<vector<int>&&>(items));
    cout << "items.size(): " << items.size() << " items2.size(): " << items2->size() << endl;
    for (int v : *items2)
        cout << "v: " << v << endl;

    delete items2;

    // 丢掉返回值.
    cout << " ===== 9 ===== " << endl;
    static_cast<void>(items.size());

    // 和C一样(T)可以强转类型, 除了 const,volatile, __unaligned 声明的属性。
    // 支持数值类型的转换, 作用和(T)一样。不过这种可以直接用(T)即可。
    cout << " ===== 10 ===== " << endl;
    char ch1 = 'a';
    cout << "ch1: " << ch1 << endl;

    int i = static_cast<int>(100.04);
    cout << "i: " << i << endl;

    ch1 = static_cast<char>(i);
    cout << "ch1: " << ch1 << endl;

    // 支持void*指针转换.
    cout << " ===== 11 ===== " << endl;
    void* fp = &i;
    int* ni = static_cast<int*>(fp);
    cout << "ni: " << *ni << endl;

    // 支持成员(变量和函数)指针向上转换(向父类). a1的实际对象是D, 通过父对象调用子函数和成员。 
    cout << " ===== 12 ===== " << endl;
    int D::*f1 = &D::d;
    cout << "a1.d: " << a1.*static_cast<int A::*>(f1) << endl;

    cout << " ===== 13 ===== " << endl;
    c.hello();

    typedef void (C::*FuncHello)();
    auto E::*f2 = &E::hello;
    (c.*static_cast<FuncHello>(f2))();

    typedef void (B::*VirtualFuncHello)();
    auto D::*f3 = &D::hello;
    (b.*static_cast<VirtualFuncHello>(f3))();


输出

Hello World!
 ===== 1 =====
A
B
D
D hello
D hello
 ===== 2 =====
A
C
E
C hello
C hello
 ===== 3 =====
D hello
 ===== 4 =====
E hello
 ===== 5 =====
A hello
A hello
 ===== 6 =====
A
B
A
C
 ===== 7 =====
A
C
 ===== 8 =====
items.size(): 3
items.size(): 0 items2.size(): 3
v: 1
v: 2
v: 3
 ===== 9 =====
 ===== 10 =====
ch1: a
i: 100
ch1: d
 ===== 11 =====
ni: 100
 ===== 12 =====
a1.d: 4
 ===== 13 =====
C hello
E hello
D hello

参考

  1. static_cast conversion - cppreference.com

  2. static_cast,reinterpret_cast,dynimic_cast的使用场景和区别 - infoworld

  3. static_cast Operator | Microsoft Learn - infoworld

  4. 左值-右值-lvalue-rvalue

  5. 类型转换的说明_infoworld的博客

  6. static_cast用法浅析_Citronnelle2的博客

以上是关于[C/C++]_[中级]_[static_cast的详细解析]的主要内容,如果未能解决你的问题,请参考以下文章

[C/C++]_[中级]_[static_cast的详细解析]

[C/C++]_[初级]_[static_cast,reinterpret_cast,dynimic_cast的使用场景和区别]

[C/C++]_[中级]_[获取月份的最后一天]

[C/C++]_[中级]_[获取月份的最后一天]

[C/C++]_[中级]_[获取月份的最后一天]

错误 C2440: 'static_cast' : 无法从 'UINT (__thiscall CImportProjectDlg::* )(CPoint)' 转换为 'LRESULT (__this