C++的四种强制转换

1.背景

大家好,我是酒馆店小二。
C风格的强制转换(Type Cast)容易理解,不管什么类型的转换都可以使用使用下面的方式。

TypeName res = (NewTypeName)ans; 

当然,C++也是支持C风格的强制转换,但是C风格的强制转换可能带来一些隐患,让一些问题难以察觉。所以C++提供了一组可以用在不同场合的强制转换的函数。

2.const_cast 常量转换

const_cast用于强制去掉不能被修改的常数特性,其去除常量性的对象一般为指针或引用。

用法:const_cast (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, new_type和expression的类型是一样的。
常量指针被转化成非常量指针,并且仍然指向原来的对象;
常量引用被转换成非常量引用,并且仍然指向原来的对象。

#include 
#include 
#include 
#include 

/*
* Author: 酒馆店小二
* Description: c++强制转换
* Date: 2022-03-10 17:14:56 星期四
* FileName: Trans.cpp
* Location: D:\VSCODE_CPP\mainshi\Trans.cpp
*/

using namespace std;

int main(int argc, char* argv[]){
    int arr[4] = {1, 2, 3, 4};  // 原始数组

    const int *c_ptr = arr;  // 常量化数组指针
    // c_ptr[1] = 233;   // error,不能通过指针的形式改变数组的值

    int *ptr = const_cast<int*>(c_ptr); // 通过const_cast 去常量
    for (int i = 0; i < 4; i++)  // 修改数据
        ptr[i] += 10;    //pass

    for (int i = 0; i < 4; i++)  // 打印修改后的数据
        cout << arr[i] << "  ";
    cout << endl;

    return 0;
}

C++的四种强制转换_第1张图片

3.static_cast 静态转换(编译时检查)

static_cast静态转换相当于C语言中的强制转换,但不能实现普通指针数据(空指针除外)的强制转换,一般用于父类和子类指针、引用间的相互转换。没有运行时类型检查来保证转换的安全性

①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。不管是否发生多态,父子之间互转时,编译器都不会报错。

进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;

进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的,但是编译器不会报错。

②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。

③把空指针转换成目标类型的空指针。

④把任何指针类型转换成空指针类型。

⑤可以对普通数据的const和non_const进行转换,但不能对普通数据取地址后的指针进行const添加和消去。

⑥无继承关系的自定义类型,不可转换,不支持类间交叉转换。

另外,static_cast不能转换掉原有类型的const、volatile、或者 __unaligned属性。(前两种可以使用const_cast 来去除)。

#include 
#include 
#include 
#include 

/*
* Author: 酒馆店小二
* Description: c++强制转换
* Date: 2022-03-10 17:14:56 星期四
* FileName: Trans.cpp
* Location: D:\VSCODE_CPP\mainshi\Trans.cpp
*/

using namespace std;

class Person {
};

class Son :public Person {
}; 

class My {};

void test02() {
    char a = 'c';
    int b = static_cast<int>(a);
    cout << b << endl; // 99

    const char a0 = 'c';
    char b0 = static_cast<char>(a0);
    cout << b0 << endl; // c

    // 父类指针转为子类,下行,编译通过,不安全
    Person *p = nullptr;
    Son *s = static_cast<Son *>(p);

    // 子类指针转为父类,上行,编译通过,安全
    Son *s0 = nullptr;
    Person *p0 = static_cast<Person *>(s0);

    // My* my= static_cast(p); 无继承关系的自定义数据类型不能相互转换

    //父类对象无法转为子类对象
    // Person p1;
    // Son s1 = static_cast(p1);

    // 子类对象可以赋值,初始化父类对象
    Son s2;
    Person p2 = static_cast<Person>(s2);

    // 父类引用转为子类,下行,编译通过,不安全
    Person p_;
    Person &p3 = p_;
    Son &s3 = static_cast<Son &>(p3);

    // 子类引用转为父类,上行,编译通过,安全
    Son s_;
    Son &s4 = s_;
    Person &p4 = static_cast<Person &>(s4);

    // 空指针转化为目标类型的指针
    void *pPtr = nullptr;
    int *iPtr = static_cast<int *>(pPtr);

    // 任何指针转化为空指针类型
    int *aInt = nullptr;
    void *aVoid = static_cast<void *>(aInt);

    // static_cast不能进行除void外的指针强制互转
    char *tmp = "abc";
    cout << tmp << endl; // abc
    // cout << static_cast(tmp) << endl; // 不能将char*型的数据转换为int*,但C语言强转可以

    int *tmpInt = 0;
    cout << tmpInt << endl; // 0
    cout << static_cast<void *>(tmpInt) << endl; // 0
    cout << static_cast<int *>(tmpInt) << endl; // 转为自身可以, 0
}

int main(int argc, char* argv[]){
    int arr[4] = {1, 2, 3, 4};  // 原始数组

    const int *c_ptr = arr;  // 常量化数组指针
    // c_ptr[1] = 233;   // error,不能通过指针的形式改变数组的值

    int *ptr = const_cast<int*>(c_ptr); // 通过const_cast 去常量
    for (int i = 0; i < 4; i++)  // 修改数据
        ptr[i] += 10;    //pass

    for (int i = 0; i < 4; i++)  // 打印修改后的数据
        cout << arr[i] << "  ";
    cout << endl;
    int a = 10;
    int b = 4;
    double result = static_cast<double>(a) / static_cast<double>(b);
    cout << result << endl; // 2.5

    double d = 7;
    void *p = &d;
    double *dp = static_cast<double*>(p);
    cout << *dp << endl; // 7

    test02();

    return 0;
}

C++的四种强制转换_第2张图片

4.dynamic_cast 动态转换(运行时检查)

动态转换的类型和操作数必须是完整类类型或空指针、空引用,说人话就是说,只能用于类间转换,支持类间交叉转换,不能操作普通数据。

主要用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换,

①进行上行转换(把派生类的指针或引用转换成基类表示)是安全的,允许转换;
②进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的,不允许转化,编译器会报错;
③发生多态时,允许互相转换。
④无继承关系的类之间也可以相互转换,类之间的交叉转换。
⑤如果dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常

#include 
#include 
#include 
#include 

/*
* Author: 酒馆店小二
* Description: dynaimc_cast
* Date: 2022-03-10 18:16:24 星期四
* FileName: dynamic_trans.cpp
* Location: D:\VSCODE_CPP\mainshi\dynamic_trans.cpp
*/
using namespace std;

class Base{
public:
    Base() {}
    ~Base() {}
    void print() {
        std::cout << "I'm Base" << endl;
    }

    virtual void i_am_virtual_foo() {}
};

class Sub: public Base{
public:
    Sub() {}
    ~Sub() {}
    void print() {
        std::cout << "I'm Sub" << endl;
    }

    virtual void i_am_virtual_foo() {}
};

int main(int argc, char* argv[]) {
    Base base;
    Sub sub;

    cout << "Sub->Base" << endl;
    sub.print();
    Sub* ps = &sub;
    Base *pb = dynamic_cast<Base*>(ps);
    if (pb != nullptr) { // 上行指针转换成功
        pb->print();
    } else {
        cout << "base> pb val is: " << pb << endl;
    }

    cout << endl << "Base->Sub" << endl;
    base.print();
    Base *pb02 = &base;
    Sub  *ps02 = dynamic_cast<Sub*>(pb02);
    if (ps02 != nullptr) { // 下行指针转换失败
        ps02->print();
    } else {
        cout <<"sub> ps02 val is: "<< ps02 << endl;
    }

    Base &refer = base;
    try
    {
        Sub &d = dynamic_cast<Sub &>(refer);
        d.print();
    }
    catch (const bad_cast &ex)
    {
        //下行引用转换失败,抛出std::bad_cast异常
        cout << ex.what();
    }

    return 0;
}

C++的四种强制转换_第3张图片

5.reinterpret_cast

在C++语言中,reinterpret_cast主要有几种强制转换用途:将指针或引用转换为一个足够长度的整型、将整型转换为指针或引用类型。

#include 
#include 

/*
* Author: 酒馆店小二
* Description: reinterpret_cast
* Date: 2022-03-10 18:53:17 星期四
* FileName: reinterpert_cast.cpp
* Location: D:\VSCODE_CPP\mainshi\reinterpert_cast.cpp
*/
using namespace std;

int main(int argc, char* argv[]) {
    int *ptr = new int(233);
    uint64_t ptr_addr = reinterpret_cast<uint64_t>(ptr);
    cout << "ptr's address: " << hex << ptr << endl
        << "ptr_addr's address: " << hex << ptr_addr << endl;
    delete ptr;
    return 0;
}

C++的四种强制转换_第4张图片
月上柳梢头,人约黄昏后。
2022.3.10

你可能感兴趣的:(c++,c++,开发语言,visual,studio)