首页 > 编程语言 >C++强制类型转换

C++强制类型转换

时间:2025-01-08 23:57:52浏览次数:3  
标签:类型转换 const int C++ cast 强制 ptr 指针

目录

一.C语言类型转换

1.自动类型转换

2.强制类型转换

二.C++强制类型转换

1. static_cast

2.const_cast

3.reinterpret_cast

4.dynamic_cast


一.C语言类型转换

1.自动类型转换

C/C++中均提供自动类型转化,适用于部分内置类型的互相转换,语法格式如下:

目标类型 b =  a;

如double c = 10.2;float d = c;发生自动类型转换,但由于double数据类型为64位,float为32位,故在转换时可能丢失数据精度,编译器会发出警告.若是不可自动类型转换的数据类型,编译器则会报错,此时需要用到强制类型转换.

2.强制类型转换

格式如下:

目标类型 b = (目标类型) a;

不管什么类型都可以直接进行转换,C++也是支持C语言的强制类型转换,但是C风格的强制类型转换可能会带来一些隐患,出现一些难以察觉的问题.

诶,这时候就有人会问了:兄弟兄弟,这个C语言类型强制转换还是太难操作了,到时候报错很难发现是类型转换出问题了怎么办?(简单,只需在编程时将其一把抓住,顷刻炼化,让它不出错就...)那有没有更加严谨,清晰的强制类型转化方法呢?

有的兄弟,有的,在C++中,新增了四个关键字static_cast、const_cast、reinterpret_cast和dynamic_cast,用于支持C++风格的强制类型转换来替代C风格的强制类型转换,降低使用风险.C++风格的强制类型转换能更清晰的表明它们要干什么,程序员只要看一眼这样的代码,立即能知道强制转换的目的,并且,在多态场景也只能使用C++风格的强制类型转换.C++风格的强制类型转换在多线程及网络编程中经常被用到.

注:C++的类型转换只是语法上的解释,本质上与C风格的类型转换没什么不同,C语言做不到事情的C++也做不到.

二.C++强制类型转换

语法:

static_cast<目标类型>(表达式);

const_cast<目标类型>(表达式);

reinterpret_cast<目标类型>(表达式);

dynamic_cast<目标类型>(表达式);

1. static_cast

static_cast是最常用的C++风格的强制类型转换,主要是为了执行那些较为合理的强制类型转换.

1)用于内置数据类型之间的转换

C风格:编译器可能会提示警告信息。

static_cast:不会提示警告信息。

#include <iostream>

using namespace std;

int main(int argc, char* argv[])

{

    int    ii = 3;

    long ll = ii;                     // 绝对安全,可以隐式转换,不会出现警告。

    double dd = 1.23;

    long ll1 = dd;                  // 可以隐式转换,但是,会出现可能丢失数据的警告。

    long ll2 = (long)dd;              // C风格:显式转换,不会出现警告。

    long ll3 = static_cast<long>(dd);    // C++风格:显式转换,不会出现警告。

    cout << "ll1=" << ll1 << ",ll2=" << ll2 << ",ll3=" << ll3 << endl;

}

2)用于指针之间的转换

C风格:可用于各种类型指针之间的转换。

static_cast:各种类型指针之间的不允许转换,必须借助void*类型作为中间介质。

#include <iostream>
using namespace std;

void func(void* ptr) {   // 其它类型指针 -> void *指针 -> 其它类型指针
    double* pp = static_cast<double*>(ptr);
}
int main(int argc, char* argv[])
{
    int ii = 10;

    //double* pd1 = &ii;                      // 错误,不能隐式转换。
    double* pd2 = (double*) &ii;      // C风格,强制转换。
    //double* pd3 = static_cast<double*>(&ii);    // 错误,static_cast不支持不同类型指针的转换。
    void* pv = &ii;                               // 任何类型的指针都可以隐式转换成void*。
    double* pd4 = static_cast<double*>(pv);  // static_cast可以把void *转换成其它类型的指针。
    func(&ii);
}

3)不能转换掉expression的const或volitale属性

#include <iostream>

int main(int argc, char* argv[])

{

    int temp = 10;

    const int* a_const_ptr = &temp;

    int* b_const_ptr = static_cast<int*>(a_const_ptr); // const int* -> int* 无效

    const int a_const_ref = 10;

    int& b_const_ref = static_cast<int&>(a_const_ref); // const int& -> int& 无效

    volatile int* a_vol_ptr = &temp;

    int* b_vol_ptr = static_cast<int*>(a_vol_ptr); // volatile int* -> int* 无效

    volatile int a_vol_ref = 10;

    int& b_vol_ref = static_cast<int&>(a_vol_ref); // volatile int& -> int& 无效

}

2.const_cast

static_cast不能丢掉指针(引用)的const和volitale属性,const_cast可以。

示例:

#include <iostream>

using namespace std;

void func(int *ii) {}

int main(int argc, char* argv[])

{

const int *aa=nullptr;

int *bb = (int *)aa;                          // C风格,强制转换,丢掉const限定符。

int* cc = const_cast<int*>(aa);      // C++风格,强制转换,丢掉const限定符。

func(const_cast<int *>(aa));

}

3.reinterpret_cast

static_cast不能用于转换不同类型的指针(引用)(不考虑有继承关系的情况),reinterpret_cast可以。

reinterpret_cast的意思是重新解释,能够将一种对象类型转换为另一种,不管它们是否有关系。

语法:reinterpret_cast<目标类型>(表达式);

<目标类型>和(表达式)中必须有一个是指针(引用)类型。

reinterpret_cast不能丢掉(表达式)的const或volitale属性。

应用场景:

1)reinterpret_cast的第一种用途是改变指针(引用)的类型。

2)reinterpret_cast的第二种用途是将指针(引用)转换成整型变量。整型与指针占用的字节数必须一致,否则会出现警告,转换可能损失精度(注:VS中指针变量为8Byte,即64位)。

3)reinterpret_cast的第三种用途是将一个整型变量转换成指针(引用)。

示例: 

#include <iostream>

using namespace std;

void func(void* ptr) {  

    long long ii = reinterpret_cast<long long>(ptr);

    cout << "ii=" << ii << endl;

}

int main(int argc, char* argv[])

{

    long long ii = 10;

  func(reinterpret_cast<void *>(ii));

}

4.dynamic_cast

dynamic_cast一般用于多态.

基类指针可以指向派生类对象,如何知道基类指针指向的是哪种派生类的对象呢?(想调用派生类中的非虚函数)。

dynamic_cast运算符用指向基类的指针来生成派生类的指针,它不能回答“指针指向的是什么类的对象”的问题,但能回答“是否可以安全的将对象的地址赋给特定类的指针”的问题。

语法:派生类指针 = dynamic_cast<派生类类型 *>(基类指针);

如果转换成功(基类指针指向的就是该派生类对象),dynamic_cast返回对象的地址,如果失败,返回nullptr。

注意:

1)dynamic_cast只适用于包含虚函数的类。

2)dynamic_cast可以将派生类指针转换为基类指针,但这种画蛇添足的做法没有意义。

3)dynamic_cast可以用于引用,但是,没有与空指针对应的引用值(在 C++ 标准中,引用不能被赋值为nullptr,因为引用必须总是引用一个有效的对象,而引用的本质--指针常量可以初始化为nullptr,但一般无意义.)

,如果转换请求不正确,会出现bad_cast异常。

示例:

#include <iostream>         // 包含头文件。

using namespace std;        // 指定缺省的命名空间。

class Hero                        // 英雄基类

{

public:

int viability;      // 生存能力。

int attack;         // 攻击伤害。

virtual void skill1() { cout << "英雄释放了一技能。\n"; }

virtual void skill2() { cout << "英雄释放了二技能。\n"; }

virtual void uskill() { cout << "英雄释放了大绝招。\n"; }

};

class XS :public Hero       // 西施派生类

{

public:

void skill1() { cout << "西施释放了一技能。\n"; }

void skill2() { cout << "西施释放了二技能。\n"; }

void uskill() { cout << "西施释放了大招。\n"; }

void show() { cout << "我是天下第一美女。\n"; }

};

class HX :public Hero       // 韩信派生类

{

public:

void skill1() { cout << "韩信释放了一技能。\n"; }

void skill2() { cout << "韩信释放了二技能。\n"; }

void uskill() { cout << "韩信释放了大招。\n"; }

};

class LB :public Hero       // 李白派生类

{

public:

void skill1() { cout << "李白释放了一技能。\n"; }

void skill2() { cout << "李白释放了二技能。\n"; }

void uskill() { cout << "李白释放了大招。\n"; }

};

int main()

{

// 根据用户选择的英雄,施展一技能、二技能和大招。

int id = 0;     // 英雄的id。

cout << "请输入英雄(1-西施;2-韩信;3-李白。):";

cin >> id;

// 创建基类指针,让它指向派生类对象,用基类指针调用派生类的成员函数。

Hero* ptr = nullptr;

if (id == 1) {             // 1-西施

ptr = new XS;

}

else if (id == 2) {      // 2-韩信

ptr = new HX;

}

else if (id == 3) {      // 3-李白

ptr = new LB;

}

if (ptr != nullptr) {

ptr->skill1();

ptr->skill2();

ptr->uskill();

// 如果基类指针指向的对象是西施,那么就调用西施的show()函数。

//if (id == 1) {

// XS* pxs = (XS *)ptr;        // C风格强制转换的方法,程序员必须保证目标类型正确。

// pxs->show();

//}

XS* xsptr = dynamic_cast<XS*>(ptr);         // 把基类指针转换为派生类。

if (xsptr != nullptr) xsptr->show();              // 如果转换成功,调用派生类西施的非虚函数。

delete ptr;

}

// 以下代码演示把基类引用转换为派生类引用时发生异常的情况。

/*HX hx;

Hero& rh = hx;

try{

XS & rxs= dynamic_cast<XS &>(rh);

}

catch (bad_cast) {

cout << "出现了bad_cast异常。\n";

}*/

}

标签:类型转换,const,int,C++,cast,强制,ptr,指针
From: https://blog.csdn.net/qq_74224788/article/details/145019416

相关文章

  • C++程序编译的过程及命名空间
    C++程序编译的过程:预处理-> 编译(优化、汇编)->链接 目录 1.预处理一、包含头文件二、宏定义指令三、条件编译2、编译和链接一、源代码的组织二、编译预处理三、编译四、链接五、更多细节3、命名空间一、语法二、使用命名空间三、注意事项四、代码示例 1......
  • C++ 复习总结记录六
    C++复习总结记录六模板初阶主要内容1、泛型编程2、函数模板3、类模板4、STL简介一泛型编程如何实现一个通用的交换函数voidSwap(int&left,int&right){inttemp=left;left=right;right=temp;}voidSwap(double&left,double&right)......
  • 【C++入门】详解(上)
    目录......
  • C++ Qt练习项目 QChar功能测试
    个人学习笔记代码仓库GitCode-全球开发者的开源社区,开源代码托管平台新建项目设计UI1、拖入group box去掉名字2、拖入2个LineEdit3、拖入两个Label4、拖入两个PushButton5、点栅格布局1、拖入GroupBox2、拖入4个PushButton3、点栅格布局1、拖入G......
  • 【C++】构造函数与析构函数
    写在前面构造函数与析构函数都是属于类的默认成员函数!默认成员函数是程序猿不显示声明定义,编译器会中生成。构造函数和析构函数的知识需要建立在有初步类与对象的基础之上的,关于类与对象不才在前面笔记中有详细的介绍:点我跳转文章目录写在前面一、构造函数的特性1.1......
  • JNI接口--实现Java调用C++
    1、JNI原理概述通常为了更加灵活高效地实现计算逻辑,我们一般使用C/C++实现,编译为动态库,并为其设置C接口和C++接口。用C++实现的一个库其实是一个或多个类的简单编译链产物,然后暴露其实现类的构造方法和纯虚接口类。这样就可以通过多态调用到库内部的实现类及其成员方法。进一步地......
  • Effective C++读书笔记——item12(自定义拷贝构造函数和拷贝赋值运算符可能出现的问题
    1.拷贝函数相关背景及编译器行为在面向对象系统中,拷贝构造函数和拷贝赋值运算符统称为拷贝函数,若不自行声明,编译器会按需生成默认的拷贝函数,其会拷贝被拷贝对象的全部数据。但当自行声明拷贝函数后,编译器若发现实现存在错误,往往不会主动提示,比如在新增数据成员却未更新拷贝函......
  • Effective C++读书笔记——item11(自赋值)
    自赋值相关问题自赋值情况示例明显的自赋值如w=w,还有不太容易辨别的情况,像a[i] =a[j](当i和j值相同)、*px=*py(当px和py指向同一对象)等,这些是由别名(有多种引用对象的方式)造成的,尤其在涉及引用、指针操作同类型多个对象以及继承体系中基类和派生类对象引用、指针转换时要考......
  • 基于C++和Yolo5检测和React前端开发的人流量检测系统源码+文档说明+详细注释(高分项目
    文章目录源码下载地址项目介绍进入后端目录安装依赖注意:确保已经安装了必要的依赖和环境启动后端服务项目功能界面预览项目备注源码下载地址源码下载地址点击这里下载代码项目介绍Yolov5-react-pedestrian-flow-monitoring-system是基于C++Yolov5检测和Reac......
  • 打卡信奥刷题(561)用C++信奥P7343[普及组/提高] 【DSOI 2021】电子跃迁
    【DSOI2021】电子跃迁题目背景“如果能证明大统一理论,这个世界将焕然一新。”“量子……量子……就差一点……”“嘶……哦。我想我明白了。”题目描述在你的视野下,出现了一排电子,他们分别拥有不同的能量。你需要做的是通过将相邻电子互换的方法,将电子排的有序。有......