C/C++类型转换

1. C类型转换

C 语言中的类型转换主要分为两种:

  1. 隐式类型转换 (Implicit Conversion) - 由编译器自动完成。

  2. 显式类型转换 (Explicit Conversion) - 由程序员强制指定,也称为强制类型转换

1.2 隐式类型转换

编译器在编译时自动进行的转换,通常发生在不同数据类型的变量混合运算、赋值或函数调用时。

转换规则(通常遵循向上转换原则):

int -> unsigned int -> long -> unsigned long -> long long -> unsigned long long -> float -> double -> long double

常见发生的场景

int i = 10;
float f = 3.14;
double d = i + f; // i 被自动转换为 float 参与运算,结果再转换为 double 赋值给 d

1.3 强制类型转换

当用户需要明确地将一种数据类型转换为另一种时使用。它使用强制类型转换运算符,语法是在要转换的目标类型前加上括号,然后放在值或表达式前面。

常见发生的场景

int a = 5, b = 2;
float result;
result = a / b;       // 错误:结果是 2.0 (整数除法)
result = (float)a / b; // 正确:结果是 2.5。将 a 转为 float,b 也会被隐式转换为 float

将 void 指针转换为具体类型指针:

void* generic_ptr;
int* int_ptr;
int x = 10;generic_ptr = &x;          // 合法:任何指针都可以赋值给 void*
// *generic_ptr;           // 错误:不能对 void* 解引用
int_ptr = (int*)generic_ptr; // 必须强制转换回 int*
printf("%d\n", *int_ptr);    // 输出 10

注意: 在 C 语言中,从 void* 转换到其他指针类型必须使用强制转换,而在 C++ 中 static_cast 可以完成这个工作,并且从 void* 到其他指针类型的隐式转换在 C++ 中是非法的。

2. C++中的类型转换

2.1 隐式类型转换

  • C++支持内置类型向自定义类型之间的转换,内置类型转换为自定义类型需要构造函数的支持。

  • C++支持自定义类型转换为内置类型,通过运算符重载 operator type () 的函数支持。

  • C++支持自定义类型向自定义类型之间的转换,需要对应类型的构造函数支持。

2.1.1 内置类型 -> 自定义类型(通过构造函数)
#include <iostream>class Meter {
private:double value;
public:// 关键:接收单一参数的构造函数// 定义了从 double -> Meter 的转换规则Meter(double val) : value(val) {std::cout << "构造函数被调用,将 double " << val << " 转换为 Meter" << std::endl;}
};int main() {Meter m1 = 5.7;     // 隐式转换:double -> Meterreturn 0;
}

注意: 使用 explicit 关键字可以禁止隐式转换,只允许显式转换

2.1.2 自定义类型 -> 内置类型(通过转换函数)

通过在类中定义 operator type() 成员函数,可以实现从自定义类型到内置类型的转换。

#include <iostream>class Meter {
private:double value;
public:Meter(double val) : value(val) {}// 转换函数:Meter -> doubleoperator double() const {std::cout << "转换函数被调用,将 Meter 转换为 double: " << value << std::endl;return value;}
};int main() {Meter m(5.7);// 自定义类型 -> 内置类型double length_in_double = m;  // 隐式调用 operator double()std::cout << "转换为 double 的值: " << length_in_double << std::endl;return 0;
}

通过operator bool()函数,可以将自定义类型当作判断条件。

2.1.3 自定义类型 -> 自定义类型(通过构造函数或转换函数)
#include <iostream>class Kilometer; // 前向声明class Meter {
private:double value;
public:Meter(double val) : value(val) {}double getValue() const { return value; }// 也可以定义到 Kilometer 的转换函数// operator Kilometer() const;
};class Kilometer {
private:double value;
public:Kilometer(double val) : value(val) {}// 关键:定义接收 Meter 参数的构造函数// 提供了 Meter -> Kilometer 的转换路径Kilometer(const Meter& m) : value(m.getValue() / 1000.0) {std::cout << "Kilometer 构造函数:将 Meter 转换为 Kilometer" << std::endl;}void display() const {std::cout << value << " kilometers" << std::endl;}
};// Meter 中转换函数的实现
// Meter::operator Kilometer() const {
//     return Kilometer(value / 1000.0);
// }int main() {Meter m(1500.0); // 自定义类型 -> 自定义类型Kilometer km = m; // 隐式转换:Meter -> Kilometerkm.display();     // 输出: 1.5 kilometersreturn 0;
}

对于转换函数,也可以使用 explicit 关键字来禁止隐式转换:

explicit operator double() const {return value;
}Meter m(5.7);
double d1 = m;          // 错误:不能隐式转换
double d2 = static_cast<double>(m); // 正确:显式转换

2.2 显示类型转换

2.2.1 static_cast

静态转换:最常用的显式转换,用于在编译期进行有明确关联的安全转换。

场景:

  • 基本数据类型之间的转换

  • void 指针与具体类型指针之间的转换

  • 类层次结构中的上行转换(派生类→基类)

int i = 10;
double d = static_cast<double>(i); // int -> doublevoid* voidPtr = &i;
int* intPtr = static_cast<int*>(voidPtr); // void* -> int*
2.2.2 reinterpret_cast

reinterpret_cast 用于在两种不相关类型之间进行转换,其本质是对原始数据的底层位模式进行重新解释,也就是说转换后对原有内存的访问解释已经完全改变了。

场景:

  • 任意指针类型之间的转换

  • 指针和整数之间的转换

int i = 0x12345678;
char* p1 = reinterpret_cast<char*>(a);
2.2.3 const_cast

const_cast⽤于const类型到⾮const类型的转换,去掉了const属性。

void oldFunction(char* str) {cout << str << endl;
}const char* message = "Hello";// oldFunction(message); // 错误:不能将 const char* 转换为 char*
oldFunction(const_cast<char*>(message)); // 正确// 危险示例!
const int ci = 10;
int* badPtr = const_cast<int*>(&ci);
*badPtr = 20; // 未定义行为!
2.2.4 dynamic_cast
  • dynamic_cast⽤于将基类的指针或者引⽤安全的转换成派⽣类的指针或者引⽤。如果基类的指针或者引⽤时指向派⽣类对象的,则转换回派⽣类指针或者引⽤时可以成功的,如果基类的指针指向基类对象,则转换失败返回nullptr,如果基类引⽤指向基类对象,则转换失败,抛出bad_cast异常。

  • 其次dynamic_cast要求基类必须是多态类型,也就是基类中必须有虚函数。因为dynamic_cast是运⾏时通过虚表中存储的type_info判断基类指针指向的是基类对象还是派⽣类对象。

场景:

  • 安全的下行转换(基类→派生类)

要求:

  • 基类必须有虚函数(多态类型)
class Base { virtual void foo() {} };
class Derived : public Base {};Base* basePtr1 = new Derived(); // 实际指向 Derived
Base* basePtr2 = new Base();    // 实际指向 Base// 安全的下行转换
Derived* d1 = dynamic_cast<Derived*>(basePtr1); // 成功
Derived* d2 = dynamic_cast<Derived*>(basePtr2); // 失败,返回 nullptrif (d2) {// 安全操作
} else {cout << "转换失败!" << endl;
}// 引用转换(失败会抛出异常)
try {Derived& rd = dynamic_cast<Derived&>(*basePtr2);
} catch (const std::bad_cast& e) {cout << "引用转换失败" << endl;
}
  • dynamic_cast 的实现基础是 RTTI(运行时类型信息)。编译器会为每个包含虚函数的类生成额外的类型信息,这些信息在程序运行时可用。

  • 什么是RTTI?

    • RTTI 是 C++ 提供的一种机制,允许程序在运行时获取和操作对象的类型信息。它让程序能够动态地确定对象的实际类型,即使是通过基类指针或引用来操作对象。

    • typeid运算符:用于获取对象的类型信息,返回一个 std::type_info 对象的引用。

    • dynamic_cast:用于在继承层次中进行安全的类型转换,依赖于 RTTI 信息。

注意:C/C++都不是类型安全的语言。

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

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

相关文章

【Java】Windows切换Java8和Java11

现在有些项目要升级到Java17, 所以需要切换不同的java版本。 如何安装Java8 由于已经安装了jJava8, 之前的安装文章&#xff1a;【Java】jdk8安装——英文版 如何安装Java17 Java17下载地址 https://www.oracle.com/java/technologies/downloads/#java17-windows 下载到电…

SQLite 数据库核心知识与 C 语言编程

一、数据库基础概念1.1 数据库分类根据规模和应用场景&#xff0c;数据库可分为以下几类&#xff1a;大型数据库&#xff1a;Oracle&#xff08;适用于企业级高并发、大容量场景&#xff09;中型数据库&#xff1a;MySQL、MSSQL&#xff08;适用于中小型系统、Web 应用&#xf…

Netty 调优篇:实战配置、性能监控与常见坑

&#x1f680; Netty 调优篇&#xff1a;实战配置、性能监控与常见坑前面我们已经深入了 Netty 的 线程模型、Pipeline、EventLoop、内存池、零拷贝和背压机制。 但在实际工作中&#xff0c;很多人踩坑的地方不是“源码没看懂”&#xff0c;而是 调优没做好。 今天我们就从三个…

Linux Node.js 安装及环境配置详细教程

如果您喜欢此文章&#xff0c;请收藏、点赞、评论&#xff0c;谢谢&#xff0c;祝您快乐每一天。 一、Node.js是什么 Node.js是一个基于Chrome V8引擎的[JavaScript运行环境]。 Node.js使用了一个事件驱动、非阻塞式I/O 的模型。 Node.js是一个让JavaScript运行在服务端的开…

呼叫中心系统IVR流程设计的心理学

呼叫中心的 IVR&#xff08;交互式语音应答&#xff09;系统看似是 “机器与用户的对话”&#xff0c;实则暗藏对用户心理的精准把握。其设计需围绕降低焦虑、提升效率、强化信任三大核心目标&#xff0c;背后依托认知心理学、行为心理学、情感心理学等理论支撑。一、认知负荷理…

一些开源或免费的网络管理工具

整理开源及免费网络管理工具推荐,涵盖监控、配置、安全、流量分析等场景,适用于不同规模的网络环境: ​一、网络监控与性能分析​ 1. ​Zabbix​ ​特点​:企业级监控方案,支持SNMP、IPMI、JMX等多种协议,提供实时仪表盘、告警通知和自动化发现功能。 ​适用场景​:服…

谷粒商城项目-P16快速开发-人人开源搭建后台管理系统

1.对脚手架工程进行改造 此项目选用的脚手架工程是人人开源 地址&#xff1a;人人开源 选择的是下图标红的renren-fast作为后端&#xff0c;renren-fast-vue作为前端 克隆上述两个项目 2.后端改造 2.1将renrenfast项目的git文件夹删除后&#xff0c;拖进后端代码文件夹中 2…

V少JS基础班之第八弹:this

文章目录一、 前言二、本节涉及知识点三、重点内容1、从新的角度认识this2、this是函数的参数3、this的值4、函数的调用1- 裸函数调用2- 函数作为构造函数调用3- 函数作为对象的方法调用4- 函数显示调用5- 箭头函数一、 前言 第八弹内容是this。this相对来说难度不大&#xff…

《堆的详解:结构、操作及堆排序算法》

目录 一.堆的概念与结构 1.1 堆的概念 1.2 堆性质&#xff1a; 1.3 堆的结构定义 二.堆的初始化和销毁 2.1 堆的初始化&#xff1a; 2.2 堆的销毁&#xff1a; 三.堆的插入数据(含向上调整算法的实现) 3.1 插入逻辑 3.2 插入函数 3.3 向上调整算法 三. 堆的删除数…

深入解析 Kubernetes 中的 Service 资源:为应用提供稳定的网络访问

什么是 Kubernetes 中的 Service&#xff1f; 在现代微服务架构中&#xff0c;服务之间的通信和负载均衡是至关重要的。尤其是在 Kubernetes 环境中&#xff0c;由于 Pod 是动态创建和销毁的&#xff0c;如何为一组 Pod 提供稳定的访问入口&#xff0c;成为了架构设计中的一个关…

使用Samba网络磁盘作为MacOS时间机器的远程备份磁盘

最近考虑MacOS系统升级&#xff0c;所以需要做磁盘备份&#xff0c;MacOS里有个备份磁盘很方便的工具&#xff1a;时间机器&#xff0c;可以自动定期备份磁盘&#xff0c;但是一般需要一个大点的移动硬盘插在macbook上选择其为备份磁盘&#xff0c;可惜我并没有移动硬盘&#x…

智能头盔实时监控系统设计与实现

智能头盔实时监控系统设计与实现 源码 https://gitee.com/intostars/csdn-demo/tree/master/src/views/smartHelmet 预览 一、功能概述 智能头盔实时监控系统是基于Vue 3和TypeScript开发的一套用于远程监控和控制智能头盔设备的前端应用模块。该系统通过WebSocket与后端服务…

Docker 学习笔记(八):容器运行时工具实践及 OpenStack 部署基础

容器管理工具Containerd nerdctl 实践 nerdctl管理存储 nerdctl命令创建容器的时候&#xff0c;可以使用-v选项将本地目录挂载给容器实现数据持久化 示例&#xff1a; [rootlocalhost ~]# mkdir /data [rootlocalhost ~]# nerdctl run -d -v /data:/data busybox -- sleep infi…

Unity键盘控制角色运动

以下是一个完整的Unity角色移动和跳跃脚本,支持WASD或方向键移动: 使用说明 确保组件设置正确: 确保您的游戏对象有一个CharacterController组件 如果没有,可以通过菜单 "Component -> Physics -> Character Controller" 添加 相机设置: 确保场景中有一…

linux 宏 DEVICE_ATTR

理解 DEVICE_ATTR DEVICE_ATTR 是 Linux 内核中用于创建设备属性的宏&#xff0c;通常用于 sysfs 文件系统。通过 sysfs&#xff0c;用户空间的程序可以读取或修改内核中的设备属性。DEVICE_ATTR 宏定义在 <linux/device.h> 头文件中&#xff0c;用于声明和定义一个设备属…

MCP模型上下文协议以及交互流程

1. MCP 是什么全称&#xff1a;Model Context Protocol定位&#xff1a;让大语言模型&#xff08;LLM&#xff09;能在“上下文”之外&#xff0c;按统一格式访问外部数据、调用插件、持久化状态。动机&#xff1a;以前每家框架&#xff08;LangChain、LlamaIndex 等&#xff0…

MySQLTransactionRollbackException

问题描述mysql部署1主3从&#xff0c;昨天发现主库有大量报警错误&#xff1a;Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction ; Deadlock found when trying to get lock; …

Redis环境搭建指南:Windows/Linux/Docker多场景安装与配置

Redis环境搭建指南&#xff1a;Windows/Linux/Docker多场景安装与配置 1. Redis安装方式概览 1.1 安装方式对比 安装方式适用场景优点缺点难度Windows直接安装开发调试安装简单&#xff0c;Windows兼容好性能不如Linux&#xff0c;生产不推荐⭐Linux源码编译生产环境性能最佳…

leetcode.80删除有序数组中的重复项2

题目描述 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。…

运动卡新手入门及常见问题处理

1.新手入门1.1 插卡打开包装&#xff0c;拿出PCI板卡&#xff0c;如下图&#xff1a;打开电脑机箱盖&#xff0c;找到PCI插槽&#xff0c;如下图&#xff08;红色框部分是PCI槽&#xff0c;有些主板上PCI槽是白色或其他颜色&#xff09;&#xff1a;插入板卡&#xff0c;如下图…