【C++】类型转换

【C++】类型转换

📝前言:

这篇文章我们来讲讲C++的类型转换

🎬个人简介:努力学习ing
📋个人专栏:C++学习笔记
🎀ZEEKLOG主页 愚润求学
🌄其他专栏:C语言入门基础python入门基础python刷题专栏Linux

文章目录

一,C语言类型转换

强制类型转换可以发生在转换有意义的地方。什么叫有意义?

  • 比如 intdouble,两个同为表示数据的大小。
  • 比如 指针(地址) 转 int,因为指针地址也是一个数字。但是不能指针转 double

类型转换发生的场景

  • 返回值接受类型和返回类型不相同
  • 形参与实参类型不相同
  • 表达式运算的项类型不相同
  • 赋值运算符,左右两边类型不相同
  • 等等…

1. 隐式类型转换

隐式类型转化:编译器在编译阶段自动动进行,能转就转,不能转就编译失败

int a =1;double b =2.1; cout << a + b << endl;// 输出 3.1

在运算时,a被隐式类型转换成了double再进行运算

2. 显式类型转换

显式强制类型转化:需要用户自己去显式在变量前用括号指定要转换的类型

int* ptr1 =&a;int c =(int)ptr1; cout << c << endl;// 输出:514849252

二,C++隐式类型转换(重点)

C++支持C语言的类型转换,同时还支持了:自定义类型 → 内置类型、内置类型 → 自定义类型、自定义类型 → 自定义类型

1. 内置转自定义

内置类型转成自定义类型需要构造函数的支持。实际上是:

  1. 把内置类型当参数,调用构造函数创建临时对象
  2. 用临时对象拷贝构造
  3. (不过上面两步可能会被编译器直接优化成一次构造)
classAdd{public:Add(int a):_a(a){}Add(int a,int b):_a(a),_b(b){}voidPrint(){ cout << _a + _b << endl;}private:int _a =1;int _b =1;};intmain(){ Add add1 =2;// 调用第一个拷贝构造 Add add2 ={2,2};// 调用第二个拷贝构造 add1.Print();// 输出 3 add2.Print();// 输出 4return0;}

如果在构造函数之前加explicit 则代表:该构造函数不能被隐式类型转换时调用。
explicit Add(int a)时,Add add1 = 2;会报错,因为创建临时对象时,无法调构造。

2. 自定义转内置

自定义转内置,要求:自定义类型内要支持:operator <转换类型>()的重载
为什么不是 <转换类型> operator(),因为这玩意已经被仿函数占用了

classA{public:A(double a):_a(a){}A(double a,int b):_a(a),_b(b){}operatordouble(){return _a;}private:double _a =1;int _b =1;};intmain(){ A a1 =2.1;double c = a1; cout << c << endl;// 输出: 2.1return0;}

3. 自定义转自定义

自定义A转自定义B:要求B有一个接受A为形参的构造函数(和内置转自定义类似)

classA{public:A(double a):_a(a){}A(double a,int b):_a(a),_b(b){}doubleGeta(){return _a;}private:double _a =1;int _b =1;};classB{public:B(A a1):_a(a1.Geta()){}voidPrint(){ cout << _a + _b << endl;}private:double _a =1.1;int _b =1;};intmain(){//A a1 = 2.1;//double c = a1;//cout << c << endl; // 输出: 2.1 A a1 =3.1; B b1 = a1; b1.Print();// 输出: 4.1return0;}

三,C++显式类型转换(重点)

1. 类型安全

类型安全指:编程语言在编译和运行时提供保护机制,避免非法的类型转换和操作。

C++并不是一门类型安全的语言,它允许我们类型转换,尽管我们可能有非法行为(这些非法行为即为不安全)
比如⼀个int*的指针强转成double*,然后用这个指针访问就会出现越界(指针的类型决定的是访问时一次"看"的空间

C++提出了4个显式的命名强制类型转换static_castreinterpret_castconst_castdynamic_cast,为了让类型转换相对而言更安全。(会检查转换是否合理)

2. 4个显式强制类型转换运算符

2.1 static_cast

static_cast

  • 检查时机:编译时
  • 使用场景:
    • 用于基本数据类型(如 int 转 double)、继承关系中的指针/引用转换(向上转换或向下转换,但是要确保安全性)
    • 不能用于无关类型(如 int* 转 double*)或移除 const 属性(把const变量转成非const不行)

示例:

double d =3.14;int i =static_cast<int>(d);// 基本类型转换 Base* base =newDerived(); Derived* derived =static_cast<Derived*>(base);// 向下转换(需确保安全)
  • 因为基类指针本身就指向派生类,再转换成派生类,不会有越界问题
  • 但是如果基类指针原本指向的就是基类,直接转换成派生类,就可能“多看”(有访问越界问题)

2.2 reinterpret_cast

reinterpret_cast

  • 检查时机:编译时
  • 用途:用于无关类型之间的转换(完全信任用户自己的行为,但是有极大的安全隐患)
    • int*char*,用户后续的访问行为可能会发生错误,引发未定义行为

示例:

int* ip =newint(42);char* cp =reinterpret_cast<char*>(ip);// 将 int* 转为 char*

2.3 const_cast

const_cast

  • 检查时机:编译时
  • 用途:添加或移除 constvolatile 属性(但是大多数是移除,因为添加可以隐式类型转换)

示例:

constint x =10;int* px =const_cast<int*>(&x);// 移除 const 属性*px =20;// 未定义行为(x 可能是常量存储区的值)volatile T* volatilePtr =...; T* nonVolatilePtr =const_cast<T*>(volatilePtr);// 移除 volatile

volatile就是用来确保每次获得变量值都去内存里面重新取,避免优化后直接从寄存器里面取,从而错过变量实际被修改了

2.4 dynamic_cast

dynamic_cast

  • 检查时机:运行时类型检查
  • 用途:用于继承体系中的安全向下转换(将基类指针或引用安全转换成派生类指针或引用)
    • 如果基类指针原本指向的就是派生类,则转换可以成功
    • 如果基类指针原本指向的指向基类,则转换失败(返回nullptr,抛出异常)
  • 要求:基类必须是多态类型(也就是基类中必须有虚函数)
    • (因为dynamic_cast是运行时通过虚表中(外)存储的type_info判断基类指针指向的是基类对象还是派生类对象)

示例:

classBase{public:virtual~Base(){}};classDerived:publicBase{}; Base* base =newDerived(); Derived* derived =dynamic_cast<Derived*>(base);// 安全向下转换if(derived){/* 成功 */}

四,RTTI

  • RTTI:运行时类型识别,程序在运行的时候才确定需要用到的对象是什么类型的。
  • RTTI 的代表运算符有两个,typeiddynamic_cast

typeid

  • typeid主要用于返回表达式的类型
  • typeid(e)e可以是任意表达式或类型的名字,typeid(e)的返回值是type_infotype_info派生类对象的引用,type_info可以只支持比较等于和不等于,name成员函数可以返回C风格字符串表示对象类型名字(不同编译器下可能不同)。可以参见:typeinfo头文件
  • e不属于类类型或者是⼀个不包含任何虚函数的类时,typeid返回的是运算
    对象的静态类型(此时是编译时确定)
  • e是定义了至少⼀个虚函数的类的左值时,typeid的返回结果直到运行时才会求得

示例(编译器为vs2022):

#include<typeinfo>intmain(){int x =42;// const std::type_info& ti = typeid(x); // typeid 返回的是 const std::type_info& std::cout <<typeid(x).name()<< std::endl;// 输出: int (不同编译器的输出效果可能不同,比如可能拿 i 表示 int)return0;}

🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

Read more

提升分布式系统响应速度:分布式系统远程调用性能提升之道

提升分布式系统响应速度:分布式系统远程调用性能提升之道

目录 一、远程调用直接案例分析 二、并行调用 (一)核心思想 (二)并行调用的实现方式 1. 基本思路 2. 代码示例 3. 关键点说明 4.线程池配置建议 三、数据异构 (一)场景重提 (二)数据异构的优点与挑战 (三)数据一致性优化 1.双写策略 2.消息队列异步更新 3.定期同步 (四)缓存管理策略优化 1.缓存预热 2.缓存穿透防护 3.缓存过期策略 (五)数据架构设计 (六)总结:异构存储的优化效果 四、混合策略 (一)设计理念  1.数据分类处理

By Ne0inhk
Flutter 三方库 health_connector_core 的鸿蒙化适配指南 - 实现具备跨平台标准的数据采集与同步架构、支持端侧健康指标建模与设备总线协同实战

Flutter 三方库 health_connector_core 的鸿蒙化适配指南 - 实现具备跨平台标准的数据采集与同步架构、支持端侧健康指标建模与设备总线协同实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 health_connector_core 的鸿蒙化适配指南 - 实现具备跨平台标准的数据采集与同步架构、支持端侧健康指标建模与设备总线协同实战 前言 在进行 Flutter for OpenHarmony 的运动健身、个人健康管理或数字疗法类应用开发时,如何统一管理来自不同传感器(如心率计、血糖仪、计步器)的异构数据?health_connector_core 是一款专注于健康数据标准化处理的底层库。它提供了从指标建模到数据聚合的完整逻辑框架。本文将探讨如何在鸿蒙端构建极致、严谨的健康数据中枢。 一、原直观解析 / 概念介绍 1.1 基础原理 health_connector_core 建立在“标准指标(Standard Metrics)”系统之上。它将杂乱无章的原生生理信号抽象为统一的 Record 模型。

By Ne0inhk
Django REST framework企业级API架构实战

Django REST framework企业级API架构实战

目录 摘要 1. 🎯 开篇:从踩坑到架构 2. 🏗️ 核心原理深度解析 2.1 DRF架构设计哲学 2.2 视图集:CRUD的终极抽象 2.3 序列化器:不只是数据转换 3. 🔧 实战:完整API实现 3.1 用户管理API 3.2 分页、过滤、排序 3.3 节流与限流 4. 🔥 高级实战:企业级API 4.1 缓存优化策略 4.2 性能监控中间件 4.3 API版本管理 5. 🚀 性能优化指南 5.1 数据库优化 5.

By Ne0inhk

RustDesk 服务端完整安装部署教程

RustDesk 服务端完整安装部署教程(2025 版) 一、环境准备 1. 服务器要求 * 操作系统:Ubuntu 20.04/22.04(推荐)、Debian、CentOS 等 * 硬件配置: * 测试环境:1 核 2G 以上 * 生产环境:2 核 4G+,50G + 存储空间 * 网络要求:公网 IP(如需外网访问) 2. 防火墙配置 开放 RustDesk 服务端所需端口: # Ubuntu/Debiansudo ufw allow 21115:21119/tcp sudo ufw allow 21116/

By Ne0inhk