【c++中的四种类型转换,应用场景】

news2025/2/26 4:36:03

c++中的四种类型转换

1.静态转换 : static_cast

用法:static_cast<type_name>(val)
1.基本类型间的转换
enum Day { Mon = 1, Tues = 2, Wed = 3, Thu = 4, Fir = 5, Sat = 6, Sun = 7 };

int main()
{
 int a = 10;
 char ch = 't';
 double dx = 21.65;
 a = static_cast<int>(ch);
 a = static_cast<int>(dx);
 Day x = Mon;
 a = x;
 x = static_cast<Day>(a);
 return 0;
}

2.指针转换
 int main()
 {
    int a = 10;
    char b = 'a';
    int* pa = &a;
    char* pb = &b;
    const int* pc = &a;
    pa = (int*)pb;  //c语言的强转,不安全
    pa = static_cast<int*>(pb);//error  类型不符合
     
    pa = (int*)pc; //c语言的强转,不安全
    pa = static_cast<int*>(pc);//error  无法去除const属性 
    return 0;
 }

总结:

1.不可以改变指针类型(特例:void型)

2.无法去除指针的const属性

3.对于void类型的指针,可以进行类型转换(如下)

int main()
{
 int a = 10;
 int* ip = nullptr;
 double* dp = nullptr;
 void* vp = &a;
 ip = static_cast<int*>(vp);
 dp = static_cast<double*>(vp);
 return 0;
}
3.左值到右值转换
int main()
{

    int a = 10;
    int &x = a;
    int &&rx = a; // error;
    int &&rx = static_cast<int &&>(a); 
    return 0;
}
4.自定义类型间的转换
class  Base
{
private:
    int  a;
public:
    Base(int x = 0) : a(x){}
};
class Obj : public Base
{
private:
	int val;
public:
	Obj(int x = 1) : val(x){}
};
class Int
{
    int val;
public:
    Int(int x = 2) : val(x){}
};
1. 不同类型间转换
int main()
{
    Base a;
    Int  b;
    Base* pa = &a;
    Int* pb = nullptr;
    pb = (Int*)pa; //c语言的强转,不安全
    pb = static_cast<Int*> (pa); //error  类型不一样
    
    return 0;
}

和内置类型一样,不行

2.上行转换
int main()
{
    Base a;
    Obj  b;
    Base* pa = &a;
    Obj* pb = &b;
    pa = pb; //隐式转换,(赋值兼容规则)
    pa = static_cast<Base*>(pb);
    
    a = b;   //隐式转换,(赋值兼容规则)
    a = static_cast<Base>(b);
    return 0;
}

注意:

隐式执行任何类型转换都可由static_cast显示完成。

static_cast不能转换掉val的const属性。

3.下行转换
int main()
{
    Base a;
    Obj  b;
    Base* pa = &a;
    Obj* pb = &b;
    pb = pa; //error ,不满足赋值兼容规则
    pb = static_cast<Obj*>(pa);
       //  pb->val 为随机值
    return 0;
}
会发生越界问题

2.去除常性转换 const_cast

用法:const_cast <type_name>(val)
特点:

1) 用于去除变量的只读属性

2) 强制转换的目标类型必须是指针或引用

1.内置类型
int main()
{
    const int a = 22; 
    const int* pb = &a;
    const int& b = a;
 
    int* pc = const_cast<int*> (pb);
    *pc  = 100;
    cout<<"a = "<<a<<" *pc = "<<*pc<<endl;
    int& la = const_cast<int&> (b);
    cout<<"a = "<<a<<" la = "<<la<<endl;
    int&& ra = const_cast<int&&> (b); 
    cout<<"b = "<<b<<"ra = "<<endl;
    return 0;
}

运行结果:

出现这种情况是因为 源程序 形成 可执行程序时需要经历4个步骤,分别是 预编译 , 编译 ,汇编, 链接 ;

其中 预编译阶段

a) 删除所有的“#define”,并且展开所有的宏定义;所有的const内置类型在预编译阶段就已经做了类似于宏替换的工作

b) 处理所有的条件预编译指令,“#if”、“#ifdef”、“#endif”等;

c) 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置;

d) 删除所有的注释;

e) 添加行号和文件名标识,以便于编译器产生调试用的符号信息及编译时产生编译错 误和警告时显示行号;

f) 保留所有的#pragma 编译器指令,因为编译器需要使用它们。

2.自定义类型
class Int
{
    int value;
public:
    Int(int x = 0) : value(x) {}
    ~Int() {}
    void SetValue(int x) { value = x; }
    int GetValue() const { return value; }
};

int main()
{
    const Int a(10);
    cout <<"a: " << a.GetValue() << endl;
    Int *ip = const_cast<Int *>(&a);
    Int &b = const_cast<Int &>(a);
    ip->SetValue(100);
    cout <<"a : " << a.GetValue() << endl;
    b.SetValue(200);
    cout <<"a : " << a.GetValue() << endl;
    system("pause");
}

运行结果:

结论:

  1. 对于自定义类型常量,不会进行类似宏替换操作。
  2. 常量指针被转化成非常量的指针,并且仍然指向原来的对象;
  3. 常量引用被转换成非常量的引用,并且仍然引用原来的对象;

3. 重新解释转换 reinterpret_cast

用法:reinpreter_cast<type_name> (val)
说明:

type_name必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换
成一个整数,也可以把一个整数转换成一个指针。类似C语言的强转。

用途:
1.用于指针类型间的强制转换 (无法去除const)
  1. 基本类型
int main()
{
 int a = 0x61626364; // a b c d

 char* p =reinterpret_cast<char*>(&a);
 cout << *p << endl;
 p += 1;
 cout << *p << endl;
 p += 1;
 cout << *p << endl;
 p += 1;
 cout << *p << endl; 
}

内存分布图:

运行结果:

  1. 自定义类型
class Object
{
private:
 int value;
public:
Object(int x = 0) :value(x) {}
 ~Object() {}
 int& Value() { return value; }
 const int& Value() const { return value; }
};

int main()
{
 Object obj(10);
 int* p = reinterpret_cast<int*>(&obj);
 int& a = reinterpret_cast<int&>(obj);
 cout << obj.Value() << endl;
 *p = 100;
 cout << obj.Value() << endl;
 a += 100;
 cout << obj.Value() << endl;
 return 0;
}

运行结果:

注:对于自定义的类型尽量不要进行此类转换,如虚基类(含有虚基类指针),有函数虚函数的类(含有虚表指针),它们的地址空间中的成员信息分布计算容易出错,导致错误访问。

2.用于整数和指针类型间的强制转换
void fun(void* p)
{
    int a = reinterpret_cast<int>(p);  //指针到整数
    cout<<a<<endl;
}
int main()
{
    int a = 100;
    fun(reinterpret_cast<void*>(a)); //整数到指针
    
    return 0;
}

运行结果:

4.动态转换 dynamic_cast

原理:RTTI

博客链接:点击跳转(建议先了解)

用法: dynamic_cast<type_name> (val)
说明:必须是公有继承,基类要有虚函数。

允许在运行时刻进行类型转换 ,从而使程序能够在一个类层次结构中安全地转换类型, 把基类指针转换成派生类指针,或把指向基类的左值转换成派生类的引用。

type_name 只能是自定义类型的指针或引用。

特点:
  1. 与C++支持的其他强制转换不同的是, dynamic_cast 是在运行时执行的类型转换。
  2. 如果针对指针类型的 dynamic_cast 失败, 则dynamic_cast 的结果是 nullptr。
  3. 如果针对引用类型的 dynamic_cast 失败, 则 dynamic_cast 会抛出一个异常。
  4. 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的。
  5. 在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

我们主要来看下行转换

class Object
{
private:
 int value;
public:
 Object(int x = 0) :value(x) {}
 virtual void func() { cout << "value: " << value << endl; }
};
class Base : public Object
{
private:
 int num;
public:
 Base(int x = 0) :Object(x + 10), num(x) {}
 void func() { cout << "num: " << num << endl; }
};

1.正确的下行转换

int main()
{
 Base base;
 Object* pobj = &base;  
 Base* pa = dynamic_cast<Base*>(pobj); //动态转换
}

图解:


运行时检查

2.错误的下行转换

int main()
{
 Base base;
 Object* pobj = nullptr;
 Object obj;
 pobj = &obj;
 Base* pa = dynamic_cast<Base*>(pobj); // 动态转换   pa = nullptr
 if(pa == nullptr) {cout << "hello world!" << endl;}
 Base* pb = static_cast<Base*>(pobj);  //不安全
}

图解:


运行时检查

运行结果:

3.引用

int main()
{
	Base base(22); 
	Object obja(11);
	Object& obj = obja;
	try 
	{
		Base& a = dynamic_cast<Base&>(obj); // 动态转换 
		a.func();
	}
	catch (std::bad_cast& e)
	{
		cout << e.what()<<endl;
	}

	Object& obj1 = base;
	Base& b = dynamic_cast<Base&>(obj1); // 动态转换 
	b.func();
}

图解:

运行结果:

结论:

使用异常给程序增加了相应的运行开销 ,所以dynamic_cast尽可能使用指针。

  1. 和void型指针结合问题
int main()
{
    Base b;
    Object& obj = b;
    void* pobj = &obj;  //正确,void型指针可以指向任意类型
    Base* pb = dynamic_cast<Base*> (pobj);  //error,pobj的类型是void(无类型信息)
}

结论:

dynamic_cast 的操作数必须是指向完整类型的指针。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1278719.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

来CSDN一周年啦!!!

各位CSDN的uu们你们好呀&#xff0c;今天是小雅兰来到CSDN创作的一周年啦&#xff0c;时间&#xff0c;说长不长&#xff0c;说短也不短&#xff0c;在这一年中&#xff0c;我认为我也收获了一些很有价值的东西吧&#xff01;&#xff01; 一周年了&#xff0c;该创作的还得继续…

正则表达式(基础、常用)

正则&#xff08;RegExp&#xff09;:用于检测字符串是否符合该规则&#xff0c;符合返回值为true,不符合返回值为false 一、定义正则表达式 1、字面量方式 const reg/a/ // 字符串中含有a即可 2、构造函数方式 const reg0new RegExp(a)二、元字符(特殊字符) 1、\d :匹…

1998-2021年全国各区县PM2.5平均浓度数据

1998-2021年全国各区县PM2.5平均浓度数据 1、时间&#xff1a;1998-2021年 2、指标&#xff1a;省、省代码、市、市代码、县代码、县、年份、均值、总和、最小值、最大值、标准差 3、来源&#xff1a;Washington university Atmospheric Composition Analysis Group 4、范围…

【Linux】-信号-(信号的产生,保存,处理,以及os是怎么读取硬件的输入,硬件异常和coredump,定时器的原理简单的用户态和内核态的详细介绍)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

SpringBoot-Vue项目初始搭建

SpringBoot-Vue项目初始搭建 1、项目搭建 前提&#xff1a;配置过nodejs环境&#xff0c;安装了vuecli&#xff08;如果未配置&#xff0c;可以参照此教程&#xff1a;https://www.bilibili.com/video/BV18E411a7mC/ p12&#xff09; 新建文件夹(最好不要有中文) 打开cmd …

AirServer怎么用?如何AirServer进行手机投屏

什么是 AirServer&#xff1f; AirServer 是适用于 Mac 和 PC 的先进的屏幕镜像接收器。 它允许您接收 AirPlay 和 Google Cast 流&#xff0c;类似于 Apple TV 或 Chromecast 设备。AirServer 可以将一个简单的大屏幕或投影仪变成一个通用的屏幕镜像接收器 &#xff0c;是一款…

C语言实现猜数字游戏

前面我们已经了解了分支循环、数据类型及变量的知识点&#xff0c;今天我将用之前学过的知识进行实操&#xff0c;将所学的知识进行巩固和提升。下面的讲解仅我个人认知水平&#xff0c;如有欠缺之处&#xff0c;欢迎大家指正&#xff0c;并且我希望初学者在看完讲解后可以独立…

汇编语言实现音乐播放器

目标程序 用汇编语言实现一个音乐播放器&#xff0c;并支持点歌 Overview 乐曲是按照一定的高低、长短和强弱关系组成的音调&#xff0c;在一首乐曲中&#xff0c;每个音符的音高和音长与频率和节拍有关&#xff0c;因此我们要分别为3首要演奏的乐曲定义一个频率表和一个节拍…

生成带依赖Jar 包的两种常用方式:IDEA打包工具:Artifacts 和 maven-shade-plugin

文章目录 前言1、IDEA打包工具&#xff1a;Artifacts1.1 创建Artifacts1.2 选择第三方jar文件1.3 打包Artifacts1.4 测试jar包 2、maven-shade-plugin2.1、pom文件添加2.2、打包2.3、测试jar包 总结 前言 当我们编写完Java程序后&#xff0c;为了提高执行效率通常会将应用程序…

MySQL5.7安装与配置:自动化一键安装配置

介绍 本文介绍了一个自动化安装MySQL的Shell脚本。该脚本可以帮助用户快速安装MySQL&#xff0c;并自动进行配置和初始化。通过使用该脚本&#xff0c;用户无需手动执行繁琐的安装步骤&#xff0c;大大简化了MySQL的安装过程。 使用shell自动化安装教程 1. 复制脚本 首先&a…

flink源码分析之功能组件(四)-slot管理组件II

简介 本系列是flink源码分析的第二个系列&#xff0c;上一个《flink源码分析之集群与资源》分析集群与资源&#xff0c;本系列分析功能组件&#xff0c;kubeclient&#xff0c;rpc&#xff0c;心跳&#xff0c;高可用&#xff0c;slotpool&#xff0c;rest&#xff0c;metrics&…

零基础打靶—CTF4靶场

一、打靶的主要五大步骤 1.确定目标&#xff1a;在所有的靶场中&#xff0c;确定目标就是使用nmap进行ip扫描&#xff0c;确定ip即为目标&#xff0c;其他实战中确定目标的方式包括nmap进行扫描&#xff0c;但不局限于这个nmap。 2.常见的信息收集&#xff1a;比如平常挖洞使用…

哈夫曼树与并查集

带权路径长度&#xff1a; 哈夫曼树定义&#xff1a; 哈夫曼树的构造&#xff1a; 哈夫曼编码&#xff1a; 并查集&#xff1a; 代码实现&#xff1a;​​​​​​​ 优化&#xff1a;​​​​​​​

ftp的服务安装配置

安装 yum install -y vsftpd # 是否安装成功 rpm -qa | grep vsftpd # 是否开机启动 systemctl list-unit-files | grep vsftpd # 开机启动 systemctl enable vsftpd.service # ftp端口 netstat -antup | grep ftp # 状态 service vsftpd status service vsftpd start service…

mybatis多表查询(xml)

多表查询都用resultMap resultMap 说白了就是他可以手动设置映射参数&#xff0c;例如 可以指定 column代表数据库的参数 property 代表实体类的参数 <id column"roleid" property"id"></id> column代表数据库的参数 property 代表实体类…

融合CFPNet的EVC-Block改进YOLO的太阳能电池板缺陷检测系统

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 随着太阳能电池板的广泛应用&#xff0c;对其质量和性能的要求也越来越高。然而&#xff0c;由于生产过程中的各种因素&#xff0c;太阳能电池板上可能存在各种缺…

人工智能和网络安全:坏与好

人工智能似乎可以并且已经被用来帮助网络犯罪和网络攻击的各个方面。 人工智能可以用来令人信服地模仿真人的声音。人工智能工具可以帮助诈骗者制作更好、语法正确的网络钓鱼消息&#xff08;而糟糕的语法往往会暴露出漏洞&#xff09;&#xff0c;并将其翻译成多种语言&…

Mongodb安装及其使用

1.Linux系统上安装Mongodb 在usr/local文件夹下创建mongo文件夹 下载mongodb包 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-6.0.5.tgz解压mongodb tar -zxvf mongodb-linux-x86_64-rhel70-6.0.5.tgz更改文件夹的名字 mv mongodb-linux-x86_64-rh…

卷积神经网络-3D医疗影像识别

文章目录 一、前言二、前期工作1. 介绍2. 加载和预处理数据 二、构建训练和验证集三、数据增强四、数据可视化五、构建3D卷积神经网络模型六、训练模型七、可视化模型性能八、对单次 CT 扫描进行预测 一、前言 我的环境&#xff1a; 语言环境&#xff1a;Python3.6.5编译器&a…

css中的 Grid 布局

flex布局和grid布局区别 flex布局是 一维布局grid布局是二维布局 flex布局示例 grid布局示例 grid 布局初体验 体验地址 <div class"wrapper"><div class"one item">One</div><div class"two item">Two</div&…