隐式转换:

基本类型的隐式转换:

当函数参数类型非精确匹配,但是可以转换的时候发生

如:

void func1(double x){cout << x << endl;
}void func2(char c){cout << c << endl;
}int main(){func1(2);//int隐式转换为doublefunc2(3);//int隐式转换为charreturn 0;
}

自定义类型的隐式转换:

函数参数列表接受类类型变量,传入的单个参数不是类对象,但可以通过这个参数调用类对应的构造函数,那么编译器就会将其隐式转换为类对象

如:

class A{
private:int a;
public:A(int x):a{x}{}
};
void func(A a){cout << "func" << endl;
}int main(){func(1);//隐式将int转换为A对象A obj = 1;//同上return 0;
}

多参数构造函数:

调用多参数构造函数时,将所有参数用用{}括起来,表示是一个初始化列表,但这并不属于自定义类型隐式转换,而是隐式构造

class A{
private:int a;
public:A(int x):a{x}{}
};class B{
private:A obj;int b;
public:B(A a,int x):obj{a},b{x}{}
};void func(B b){cout << "func" << endl;
}
int main(){func({A{1}, 2});//使用{A,int}隐式构造B对象func({1,2});//仍能运行,隐式将1转换为A对象,然后用{A,int}隐式构造B对象return 0;
}

值得注意:

自定义的类型转换不能连续发生两次以上,否则会报错

例如:

class A{
private:string str;
public:A(const string& s):str{s}{}
};void func(A a){cout << "func"<<endl;
}int main(){func("Hello");//报错,因为需要将const char*隐式转换为string,string转换为const string,//再将string隐式转换为A//需要发生两次自定义类型隐式转换func(string{"Hello"});//编译通过,只需要string转换为const string,再将string隐式转换为A,//只发生一次自定义类型隐式转换return 0;
}

禁止任何隐式调用的关键字:explicit

在类构造函数前加上explicit关键字,则该构造函数无法再被隐式转换或隐式构造

从而防止某些错误的函数调用,比如想传入int却被隐式转换为了类对象

class A{
public:explicit A(int x){cout << x << endl;}explicit A(int x,int y){cout << x << y << endl;}
};A func(int a,int b){return {a, b};//禁止{int,int}到A的隐式构造
}A func(int x){return A{x};//合法return A{x, x};//合法
}int main(){A a = 1;//禁止int到A的隐式转换return 0;
}
好习惯:

将所有接受单个参数(包括多个参数,但只有一个参数没有缺省值的)的构造函数都限定为explicit

拷贝构造和移动构造不应该限定为explicit

显式转换:

初始化列表式转换:

使用type{var}的方式进行转换,如int{'c'}

这种转换只允许小范围变量向大范围变量转换,不允许反向,如

int x{3.5};//不被允许截断
long long y{3};
cout<<double{y}<<endl;//不允许被截断

C风格转换:

使用类似(int),或者int()的方式来转换类型,底层是组合调用了C++的各种cast函数来进行转换,因此不推荐使用这种转换

在这种转换中,尝试的cast调用顺序:

const_cast

static_cast

static_cast+const_cast

reinterpret_cast

reinterpret_cast+const_cast

const_cast转换:

实际极少使用

使用方式:

const_cast<to_type>(var)

作用:

给变量添加/去除const属性

如果该变量本身就是const变量,则无法真正地去除const属性

例如:

int main(){const int x = 2;const int *p = &x;int *p2 = const_cast<int *>(p);*p2 = 3;cout << x << endl;cout << *p2 << endl;return 0;
}

输出:

2
3

这里我们试图去除p所指向的的变量的const属性,并通过p2来修改其值,但在打印x时输出的值仍为2,这是因为编译器在编译的时候知道x为const变量,因此将cout<<x直接优化成了cout<<2,从而保证了其不会被修改。

而我们尝试使用p2去修改x的值,这属于未定义行为,需避免。因此,对于本身为const属性的变量,我们不应该使用const_cast来去除其const属性,否则可能会导致未定义行为

const_cast用于去除本来不是const变量的const属性

如:

void func(const int*p){int *p2 = const_cast<int *>(p);//用来去除被函数传参过程中隐式添加的const属性*p2 = 6;
}int main(){int x = 3;const int *p = const_cast<const int *>(&x);//人为为其添加const属性,使其无法被修改//在经过了一段时间的应用后,现在又想修改x的值了int *p2 = const_cast<int *>(p);*p2 = 5;cout << *p << endl;func(&x);cout << *p << endl;return 0;
}

static_cast转换:

使用方式:

static_cast<to_type>(var)

作用:

1.进行基本类型之间的转换(允许截断,告诉编译器是有意为之的截断)

相比之下,列表初始化转化不允许截断,因此更推荐使用static_cast进行转换,当然程序员要负起截断的责任,告诉大家这是有意为之的截断,而不是自己大意导致的截断

int x=static_cast<int>(3.14);

2.进行安全性检查,不允许无关类型指针互转

int main(){double x = 3.2;int *p2 = static_cast<int *>(&x);//不合法return 0;
}

3.可以将void*指针转为任意类型指针

无安全性检查,需要保证指向的类型正确(下例为不正确用法)

int main(){double x = 3.2;int *p2 = static_cast<int *>(static_cast<void*>(&x));//通过double*转void*,再从void*转到int*,跳过了安全性检查return 0;
}

4.将派生类指针/引用/对象转换为基类指针/引用/对象(向上转换)

class Base{
};
class Derived:public Base{
};
int main(){Base *p_b = static_cast<Base *>(new Derived);Derived d;Base &ref_b = static_cast<Base &>(d);Base obj_b = static_cast<Base>(d);//导致对象切片
}

5.将基类指针/引用转换为派生类指针/引用(向下转换,不推荐)

无安全性检查,需要保证基类指针指向要转换的派生类或者其派生类

若基类派生类拥有虚函数,应优先使用dynamic_cast(下文讲解)

Base* p_b2=new Derived;
Derived* p_d=static_cast<Derived*>(p_b2);//合法

6.显式调用自定义构造函数/类型转换函数进行转换

class MyInt {
public:explicit MyInt(int x) : value(x) {}operator int() const { return value; }  // 自定义的转换运算符
private:int value;
};MyInt mi = static_cast<MyInt>(42);  // 调用构造函数
int x = static_cast<int>(mi);       // 调用 operator int()

dynamic_cast转换:

使用方式:

dynamic_cast<Derived_ptr/Derived_ref>(Base_ptr/Base_ref);

作用:

仅能对拥有虚函数的基类/派生类使用,且不能是protected/private继承关系

基类为虚基类时,在某些情况会导致dynamic_cast失败

对基类的指针/引用进行安全检查的向下转换(转换为派生类指针/引用)

也可进行向上转换(不推荐,应使用static_cast)

返回值:

若转换成功,即Base_ptr/Base_ref实际指向的对象是Derived对象或者是其派生类对象,则返回指向该对象的Derived_ptr/Derived_ref

若转换失败,即Base_ptr/Base_ref实际指向的是别的东西,则返回nullptr

值得注意的是:

dynamic_cast依赖于RTTI(run-time type information)来确定指针指向对象的实际类型从而进行转换,因此,没有虚函数,或者关闭了RTTI优化,都会导致对象的RTTI信息丢失,从而导致dynamic_cast失败

reinterpret_cast转换:

该转换无安全性检查,直接重新解释对象的二进制比特模式

高安全风险,极少使用,不推荐

使用方式:

reinterpret_cast<to_type>(var);

作用:

1.任意类型之间的指针互转

2.指针与整数互转

3.函数指针与数据指针互转

4.任意数据类型互转

路径不确定导致的转换二义性:

1.非虚继承的菱形继承的向上转换:

此时将指向D对象的D指针向上转换为A指针时,会出现二义性错误,因为编译器不知道指向哪个A对象,这种情况下,只能一层一层地向上转换,直到产生二义性的路径消失,方可一次性转换到A

2.虚继承导致的菱形继承的向下转换:

此时将指向E对象的A指针向下转换为B指针时,会出现二义性错误,因为编译器不知道指向哪个B对象,而且虚继承导致指针偏移无法计算(虚继承机制以后的文章再讲解),这种情况下,只能先转成E指针,再向上转换,直到二义性路径消失

3.同层交叉cast转换:

可以直接将指向E对象的D指针用dynamic_cast转换为B指针

只需要满足B和D没有共同的虚基类即可(有的话,会导致指针偏移无法计算,从而dynamic_cast失败),有的话,使用第二点的方法

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2.重建大师输入输出数据格式介绍

摘要&#xff1a;本文主要介绍重建大师支持的输入数据格式及输出数据格式。 1.输入数据格式 1.1图像文件 重建大师支持JPG、JPEG和TIFF格式的照片。 不同架次照片放置于同级目录的不同文件夹&#xff0c;同一架次不同镜头拍摄得到的照片存放于不同的子文件夹&#xff0c;可使…

我们该如何使用DeepSeek帮我们减负?

在当今信息爆炸的时代&#xff0c;如何快速获取、筛选和分析信息已经成为各行各业的重要能力。而DeepSeek作为一种先进的智能搜索和信息挖掘工具&#xff0c;能够帮助用户快速找到所需的信息&#xff0c;并从海量数据中提取出有用的洞见。在这篇博文中&#xff0c;我们将深入探…

抗量子计算攻击的数据安全体系构建:从理论突破到工程实践

在“端 - 边 - 云”三级智能协同理论中&#xff0c;端 - 边、边 - 云之间要进行数据传输&#xff0c;网络的安全尤为重要&#xff0c;为了实现系统总体的安全可控&#xff0c;将构建安全网络。 可先了解我的前文&#xff1a;“端 - 边 - 云”三级智能协同平台的理论建构与技术实…

支付宝API-SKD-GO版

前言 支付宝api的sdk没有提供go版&#xff0c;这里自己封装了一个go版的sdk&#xff0c;有需要的朋友可以自取使用 支付宝 AliPay SDK for Go, 集成简单&#xff0c;功能完善&#xff0c;持续更新&#xff0c;支持公钥证书和普通公钥进行签名和验签。 Github地址 GitHub - …

JAVA研发+前后端分离,ZKmall开源商城B2C商城如何保障系统性能?

在电商行业竞争白热化的当下&#xff0c;B2C 商城系统的性能表现成为决定用户留存与商业成败的关键因素。ZKmall 开源商城凭借 Java 研发与前后端分离架构的深度融合&#xff0c;构建起一套高效、稳定且具备强大扩展性的系统架构&#xff0c;从底层技术到上层应用全方位保障性能…

volatile是什么

一、背景和问题描述 假设你写的这个多线程程序中&#xff0c;有两个线程&#xff1a; 子线程&#xff08;thr&#xff09;&#xff1a;把flag变量设为1&#xff0c;并输出“modify flag to 1”&#xff1b;主线程&#xff1a;一直在循环等待&#xff0c;直到flag变成1&#x…

MySQL的Docker版本,部署在ubantu系统

前言 MySQL的Docker版本&#xff0c;部署在ubantu系统&#xff0c;出现问题&#xff1a; 1.执行一个SQL&#xff0c;只有错误编码&#xff0c;没有错误提示信息&#xff0c;主要影响排查SQL运行问题&#xff1b; 2.这个问题&#xff0c;并不影响实际的MySQL运行&#xff0c;如…

专栏特辑丨悬镜浅谈开源风险治理之SBOM与SCA

随着容器、微服务等新技术日新月异&#xff0c;开源软件成为业界主流形态&#xff0c;软件行业快速发展。但同时&#xff0c;软件供应链也越来越趋于复杂化和多样化&#xff0c;软件供应链安全风险不断加剧。 软件供应链安全主要包括软件开发生命周期和软件生存运营周期&#x…

18.Excel数据透视表:第1部分创建数据透视表

一 什么是数据透视表 通过万花筒可以用不同的方式査看里面画面图像&#xff0c;在excel中可以将数据透视表看作是对准数据的万花筒&#xff0c;用不同角度去观察数据&#xff0c;也可以旋转数据&#xff0c;对数据进行重新排列&#xff0c;对大量的数据可以快速的汇总和建立交叉…

商业航天运动控制系统中的高可靠性芯片解决方案:挑战、策略与应用研究

摘要&#xff1a;随着商业航天领域的迅速发展&#xff0c;运动控制系统对芯片的可靠性提出了前所未有的挑战。本文深入探讨了商业航天运动控制系统中芯片可靠性面临的挑战&#xff0c;包括宇宙辐射效应、极端环境适应性及系统级可靠性保障等。同时&#xff0c;通过案例研究展示…

音视频学习:使用NDK编译FFmpeg动态库

1. 环境 1.1 基础配置 NDK 22b (r22b)FFmpeg 4.4Ubuntu 22.04 1.2 下载ffmpeg 官网提供了 .tar.xz 包&#xff0c;可以直接下载解压&#xff1a; wget https://ffmpeg.org/releases/ffmpeg-4.4.tar.xz tar -xvf ffmpeg-4.4.tar.xz cd ffmpeg-4.41.3 安装基础工具链 sudo …

前端开发避坑指南:React 代理配置常见问题与解决方案

前端开发避坑指南:React 代理配置常见问题与解决方案 一、为什么需要配置代理?二、使用 create-react-app 默认配置代理三、使用 http-proxy-middleware 配置复杂代理四、高级代理配置五、生产环境中的代理配置一、为什么需要配置代理? React 应用在开发过程中经常需要与后端…

用影刀RPA打通内容创作“最后一公里”:CSDN草稿一键同步多平台发布

文章目录 引言 一、需求场景&#xff1a;多平台分发的效率困境1. 痛点分析2. 影刀RPA的破局价值 二、影刀RPA是啥&#xff1f;打工人逆袭神器&#xff01;三、手把手教你造"搬运工"——技术宅的土味开发日记第一步&#xff1a;当个"偷窥狂"——观察手动操作…

进程与线程:09 进程同步与信号量

课程引入&#xff1a;进程同步与信号量 接下来这节课开始&#xff0c;我们再开始讲多进程图像。讲多进程图像的下一个点&#xff0c;前面我们讲清楚了多进程图像要想实现切换&#xff0c;调度是如何做的。同时&#xff0c;多个进程放在内存中&#xff0c;就会存在多进程合作的…

【愚公系列】《Manus极简入门》036-物联网系统架构师:“万物互联师”

&#x1f31f;【技术大咖愚公搬代码&#xff1a;全栈专家的成长之路&#xff0c;你关注的宝藏博主在这里&#xff01;】&#x1f31f; &#x1f4e3;开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主&#xff01; &#x1f…

MySQL 8.0 OCP 英文题库解析(四)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题26~30 试题26:…

什么是原码和补码

补码的本质确实是模运算&#xff08;Modular Arithmetic&#xff09;&#xff0c;这是理解补码为何能统一加减法的核心数学原理。下面用最通俗的语言和例子解释清楚&#xff1a; —### 1. 先理解什么是“模运算”- 模运算就是“周期性计数”&#xff0c;比如钟表&#xff1a; -…

笔记项目 day02

一、用户登录接口 请求参数&#xff1a; 用loginDTO来封装请求参数&#xff0c;要加上RequestBody注解 响应参数&#xff1a; 由于data里内容较多&#xff0c;考虑将其封装到一个LoginUser的实体中&#xff0c;用户登陆后&#xff0c;需要生成jwtToken并返回给前端。 登录功…

2025年土木建筑与水利工程国际会议(ICCHE 2025)

2025 International Conference on Civil and Hydraulic Engineering (ICCHE 2025) &#xff08;一&#xff09;会议信息 会议简称&#xff1a;ICCHE 2025 大会地点&#xff1a;中国银川 投稿邮箱&#xff1a;icchesub-paper.com 收录检索&#xff1a;提交Ei Compendex,CPCI,C…

运行Spark程序-在shell中运行1

&#xff08;一&#xff09;分布式计算要处理的问题 【老师提问&#xff1a;分布式计算要面临什么问题&#xff1f;】 【老师总结】 分布式计算需要做到&#xff1a; 1.分区控制。把大的数据拆成一小份一小份的&#xff08;分区&#xff0c;分片&#xff09;让多台设备同时计算…