c++积累11-强制类型转换运算符(static_cast/reinterpret_cast/const_cast/dynamic_cast)

文章详细介绍了C++中为改进C语言转换机制而引入的四种强制类型转换运算符:static_cast、reinterpret_cast、const_cast和dynamic_cast,包括它们的用途、示例和安全性。static_cast用于低风险的转换,如基本类型间的转换;reinterpret_cast提供更大的灵活性但需程序员确保安全性;const_cast用于去除const属性;dynamic_cast则用于多态类型的安全转换。

1、背景

将类型名作为强制类型转换运算符的做法是C语言的老式做法,C++为保持兼容而予以保留。强制类型转换是有一定风险的,C++引入新的转换机制,主要为了客服C语言转换的三个缺点;
1、没有从形式上体现转换功能和风险的不同。
例如,将int转换位double是没有风险的,而将常量指针转换为非常量指针,将基类指针转换为派生类指针都是高风险的,而且后两者带来的风险不同(可能引发不同的类的错误),C语言的强制类型转换形式对这些不同并不加以区分。
2、将多态基类指针转换为派生类指针不做安全性检查,即无法判断转后的指针确实指向一个派生类指针。
3、难以在程序中寻找到底什么地方做了强制类型转换。

因此,C++引入了4种不同的强制类型转换运算符:
static_cast, reinterpret_cast,const_cast,dynamic_cast

使用方式:

强制类型转换运算符 <要转换到的类型> (待转换的表达式)

例如:

double d = static_cast <double> (3*5);  //将 3*5 的值转换成实数

2、static_cast

static_cast 用于比较”自然“和低风险的转换。如整形和浮点型、字符型之间的相互转换。

#include <iostream>
using namespace std;
class A
{
public:
    operator int() { return 1; }
    operator char*() { return NULL; }
};
int main()
{
    A a;
    int n;
    char* p = "New Dragon Inn";
    n = static_cast <int> (3.14);  // n 的值变为 3
    cout << n << endl; // 输出3
    n = static_cast <int> (a);  //调用 a.operator int,n 的值变为 1
    cout << n << endl; // 输出1
    p = static_cast <char*> (a);  //调用 a.operator char*,p 的值变为 NULL
    cout << p << endl; // 输出空
    n = static_cast <int> (p);  //编译错误,static_cast不能将指针转换成整型
    p = static_cast <char*> (n);  //编译错误,static_cast 不能将整型转换成指针
    return 0;
}

在这里插入图片描述

3、reinterpret_cast

reinterpret_cast用于各种不同类型的指针之间、不同类型的引用之间、指针和能容纳指针的整数类型之间转换。这种转换提供了很强的灵活性,但是转换的安全性只能由程序员保证。

#include <iostream>

using namespace std;

class A {
public:
    int i;
    int j;
    string s = "test";

    A(int n) : i(n), j(n) {}

    void printA();
};

void A::printA() {
    cout << "i = " << i <<", j = " << j << endl;
}

int main() {
    A a(100);
    a.printA(); // i = 100, j = 100
    auto &r = reinterpret_cast<int &>(a); // 强行让r引用a
    cout << "r = " << r << endl;  // r = 100
    r = 200;
    a.printA(); //i = 200, j = 100

    int n = 300;
    A *pa = reinterpret_cast<A *>(&n); // 强行让pa指向n
    pa->printA(); // i = 300, j = 1838326408
    pa->i = 400;
    pa->j = 500; // 此语句不安全,有可能导致程序崩溃
    pa->printA(); // i = 400, j = 500
    cout << n << endl; // 400


    long long  la = 0x12345678adcdLL;
    pa = reinterpret_cast<A *>(&la); // la 太长,只取低32位0x5678adcd 拷贝给pa
    pa->printA(); // i = 1450749389, j = 4660
    cout << hex << pa->i << endl; // 5678adcd

    typedef void (*PF1) (int);
    typedef int (*PF2)(int, char *);
    PF1 pf1;
    PF2 pf2;
    pf2 = reinterpret_cast<PF2>(pf1); //两个不同类型的函数指针之间可以互相转换


    return 0;
}

4、const_cast

const_cast 运算符仅用于进行去除const属性的转换,它是4个强制类型转换中唯一能去除const属性的运算符。

  	const string a = "ddd";
    string &p = const_cast<string &>(a);
    string *ps = const_cast<string *>(&a);
    cout << a << "," << p << "," << *ps << endl; // ddd,ddd,ddd

5、dynamic_cast

用 reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换为派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。dynamic_cast专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。
dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。

#include <iostream>

using namespace std;

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {
};

int main() {
    Base b;
    Derived d;
    Derived *pd;

    pd = reinterpret_cast<Derived *>(&b);
    if (pd == NULL) {
        // 此处pd不会为NULL。reinterpret_cast 不做安全性检查,总是做转换
        cout << "unsafe reinterpret_cast " << endl; // 不会执行
    }

    pd = dynamic_cast<Derived *>(&b);
    if (pd == NULL) { //结果会是NULL,因为 &b 不指向派生类对象,此转换不安全
        cout << "unsafe dynamic_cast1 " << endl; // 会执行
    }

    pd = dynamic_cast<Derived *>(&d); // 安全的转换
    if (pd == NULL) { //此处 pd 不会为 NULL
        cout <<"safe dynamic_cast 2" << endl; //不会执行
    }


    return 0;
}

在这里插入图片描述

参考文章:http://c.biancheng.net/view/410.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值