【C++进阶】详解C++类型转换IO流

C++类型转换及IO流

  • 一,C语言的类型转换方式
  • 二,C++的四种强制类型转换方式
    • 2.1 static_cast
    • 2.2 reinterpret_cast
    • 2.3 const_cast
    • 2.4 dynamic_cast
  • 三,C语言的输入和输出
  • 四,C++的标准IO流
  • 五,C++文件IO流
  • 总结

这一节我们来讲解 C++的强转类型和IO流

一,C语言的类型转换方式

对于C语言,有两种类型转化的方式:
1. 隐式类型转换

对于意义相近的类型,比如int,double都表示数据的大小,就可以隐式类型转换

2. 显式类型转换

也就是强制类型转换

void Test ()
{
	int i = 1;
	// 隐式类型转换
	double d = i;
	printf("%d, %.2f\n" , i, d);
	int* p = &i;
	// 显示的强制类型转换
	int address = (int) p;
	printf("%x, %d\n" , p, address);
}

C语言的转换格式很简单,但是有不少缺点的:

  1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰

二,C++的四种强制类型转换方式

因此C++提出了自己的类型转化风格,因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格。

C++有四种强转类型,我们下面逐一进行讲解:

2.1 static_cast

static_cast其实就是对应C语言的隐式类型转换所以不能用于两个不相关的类型进行转换。static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast

double d = 1.1;
int aa = static_cast<int>(d);
int* ptr = static_cast<int*>(d);//这个是不可以的,因为意义不相同

2.2 reinterpret_cast

reinterpret_cast相当于C语言的强制类型转换,reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型

上面代码中的ptr是不能用static_cast转换的,所以就要用到reinterpret_cast

int* ptr = reinterpret_cast<int*>(a);

2.3 const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值

const int a = 2;
int* p = const_cast<int*>(&a);
*p = 3;

cout << a << " " << *p << endl;
cout << &a <<"    "<< p << endl;

这里打印出来后可以看到a和p的地址是一样的,但是值不一样
在这里插入图片描述
这里其实是编译器做了优化,a是const属性,所以编译器认为不会被修改,会把a直接放进寄存器中,当打印a时,直接用2去替换了a。所以显示为2。

这里就需要加上volatile破除编译器的优化,把a放入内存而不是寄存器中,打印时a的值是3

volatile const int a = 2;

2.4 dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)

向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

注意:
1. dynamic_cast只能用于父类含有虚函数的类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0

class A {
	virtual void fun(){}

	int a = 0;
};

class B : public A {
	int b = 1;
};

向上转型:把子类赋给父类
我们在前面讲过赋值兼容转移,所以这里不做过多解释。

int main() {
	B objb;
	A obja = objb;//赋值兼容转移
	A& ra = objb;//说明没有类型转换

	double d = 1.1;
	const int& a = d;//这里发生了类型转换,类型转换会产生临时变量,临时变量有常性,所以要加上const

	return 0;
}

向下转型:把父类赋给子类(父类对象不能转换为子类对象,但是父类的指针或者引用可以转换为子类的指针或者引用)

class A
{
public:
	virtual void f() {}

	int a = 0;
};

class B : public A
{
public:
	int b = 1;
};

void fun(A* pa)
{

	B* ptr = (B*)pa;//直接转是不安全的
	ptr->a++;
	ptr->b++;

	B* ptr = dynamic_cast<B*>(pa);
	if (ptr) {//如果转回子类时原本就是子类
		ptr->a++;
		ptr->b++;
	}
	else {//转回子类时原本是父类
		//..
	}


	// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
	/*B* pb1 = static_cast<B*>(pa);
	B* pb2 = dynamic_cast<B*>(pa);
	cout << "pb1:" << pb1 << endl;
	cout << "pb2:" << pb2 << endl;*/
}

int main()
{
	A a;
	B b;
	fun(&a);
	fun(&b);
	return 0;
}

三,C语言的输入和输出

C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制。C语言借助了相应的缓冲区来进行输入与输出

在这里插入图片描述
对于输入输出缓冲区来说:
1.可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,可以很容易写出可移植的程序
2.可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,有了这部分,就可以定义“行”的概念,然后解析缓冲区的内容,返回一个“行”

四,C++的标准IO流

C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类

在这里插入图片描述
C++标准库提供了4个全局流对象cin、cout、cerr、clog,使用cout进行标准输出,即数据从内存流向控制台(显示器)。使用cin进行标准输入即数据通过键盘输入到程序中,同时C++标准库还提供了cerr用来进行标准错误的输出,以及clog进行日志的输出,从上图可以看出,cout、cerr、clog是ostream类的三个不同的对象,因此这三个对象现在基本没有区别,只是应用场景不同。


这里还要注意:

  1. cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
  2. 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对应位置位(置1),程序继续。
  3. 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格。回车符也无法读入。
  4. cin和cout可以直接输入和输出内置类型数据,原因:标准库已经将所有内置类型的输入和输出全部重载了
  5. 对于自定义类型,如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载

五,C++文件IO流

C++根据文件内容的数据格式分为二进制文件文本文件
采用文件流对象操作文件的一般步骤如下:

  1. 定义一个文件流对象:
    ifstream ifile(只输入用)
    ofstream ofile(只输出用)
    fstream iofile(既输入又输出用)
  2. 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系
  3. 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写
  4. 关闭文件
struct ServerInfo
{
	char _address[32];
	int _port;
	Date _date;
};
struct ConfigManager
{
public:
	ConfigManager(const char* filename)
		:_filename(filename)
	{}
	
	void WriteBin(const ServerInfo& info)
	{
		ofstream ofs(_filename, ios_base::out | ios_base::binary);
		ofs.write((const char*)&info, sizeof(info));
	}
	void ReadBin(ServerInfo& info)
	{
		ifstream ifs(_filename, ios_base::in | ios_base::binary);
		ifs.read((char*)&info, sizeof(info));
	}

	void WriteText(const ServerInfo& info)
	{
		ofstream ofs(_filename);
		ofs << info._address << " " << info._port<< " "<<info._date;
	}
	void ReadText(ServerInfo& info)
	{
		ifstream ifs(_filename);
		ifs >> info._address >> info._port>>info._date;
	}
private:
	string _filename; // 配置文件
};
int main()
{
	ServerInfo winfo = { "192.0.0.1", 80, { 2022, 4, 10 } };
	// 二进制读写
	ConfigManager cf_bin("test.bin");
	cf_bin.WriteBin(winfo);
	ServerInfo rbinfo;
	cf_bin.ReadBin(rbinfo);
	cout << rbinfo._address << " " << rbinfo._port <<" "
	<<rbinfo._date << endl;
	// 文本读写
	ConfigManager cf_text("test.text");
	cf_text.WriteText(winfo);
	ServerInfo rtinfo;
	cf_text.ReadText(rtinfo);
	cout << rtinfo._address << " " << rtinfo._port << " " <<
	rtinfo._date << endl;
	return 0;
}

总结

到这里我们C++的知识就要这里基本结束了,后面我还会带来更多的其他内容,请大家继续关注哦

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

`Spring Cloud OpenFeign`底层实现原理

Spring Cloud OpenFeign工作原理 一 、简介 OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解&#xff0c;如RequesMapping等等。 OpenFeign的FeignClient可以解析SpringMVC的RequestMapping注解下的接口&#xff0c;并通过动态代理的方式产生实现类&#xff…

【Git】初识 Git

文章目录 1. 提出问题2. 如何解决&#xff1f;版本控制器3. 注意事项 1. 提出问题 不知道你工作或学习时&#xff0c;有没有遇到这样的情况&#xff1a;我们在编写各种文档时&#xff0c;为了防止文档丢失、更改失误、失误后能恢复到原来的版本&#xff0c;不得不复制出一个副…

Apifox接口测试教程(一)接口测试的原理与工具

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

「GO基础」GO程序组成要素

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

力扣爆刷第119天之CodeTop100五连刷81-85

力扣爆刷第119天之CodeTop100五连刷81-85 文章目录 力扣爆刷第119天之CodeTop100五连刷81-85一、14. 最长公共前缀二、718. 最长重复子数组三、169. 多数元素四、662. 二叉树最大宽度五、128. 最长连续序列 一、14. 最长公共前缀 题目链接&#xff1a;https://leetcode.cn/pro…

腾讯清华联合提出图像到视频生成方法-Follow-Your-Click:点击图像并加上简单提示词就可让图像动起来!

Follow-Your-Click只需单击一次和简短的提示就可以让图像的某一部分动起来&#xff0c;还支持不同的动作表达&#xff0c;比如微笑&#xff0c;悲伤&#xff0c;跳舞…… 相关链接 论文链接&#xff1a;https://arxiv.org/abs/2403.08268 项目链接&#xff1a;https://github…

【每日刷题】Day16

【每日刷题】Day16 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 2. 160. 相交链表 - 力扣&…

IGBT基本工作原理、主要参数及作用

IGBT是一种三端子的半导体开关器件&#xff0c;栅极&#xff0c;集电极和发射极。它结合了MOSFET的高输入阻抗和双极型三极管的低导通压降特性&#xff0c;广泛应用于变频器、电动汽车、电力传输等领域。 工作原理 IGBT由N沟道MOSFET和PNP双极型晶体管组成&#xff0c;其导通和…

前端ocr技术:electron+vue3中使用tesseract插件识别图片中字符

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、electron各种csp问题二、试用插件总结 前言 项目需要ocr技术识别图片中的中文字符&#xff0c;本来这部分是后端的工作&#xff0c;但是因为各种原因&#xff0c;决定前端也做一个版本。 在ai时代之前&#xff0c;o…

conda新建环境报错An HTTP error occurred when trying to retrieve this URL.

conda新建环境报错如下 cat .condarc #将 .condarc文件中的内容删除&#xff0c;改成下面的内容 vi .condarc channels:- defaults show_channel_urls: true default_channels:- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main- https://mirrors.tuna.tsinghua.…

如何评估一个RAG(检索增强生成)系统

本文首发自博客文章 如何评估一个RAG&#xff08;检索增强生成&#xff09;系统 RAG 概念最初来源于 2020 年 Facebook 的一篇论文&#xff0c;这是 Facebook 博客对论文内容的进一步解释 &#x1f449;《检索增强生成&#xff1a;简化智能自然语言处理模型的创建》。大家都知…

Vitis HLS 学习笔记--readVec2Stream 函数-探究

目录 1. 高效内存存取的背景 2. readVec2Stream() 参数 3. 函数实现 4. 总结 1. 高效内存存取的背景 在深入研究《Vitis HLS 学习笔记--scal 函数探究》一篇文章之后&#xff0c;我们对于scal()函数如何将Y alpha * X这种简单的乘法运算复杂化有了深刻的理解。本文将转向…

商家转账到零钱全攻略:开通、使用、区别与常见问题解答

商家转账到零钱是什么&#xff1f; 【商家转账到零钱】可以说是【企业付款到零钱】的升级版&#xff0c;商家转账到零钱可以为商户提供同时向多个用户微信零钱转账的能力&#xff0c;支持分销返佣、佣金报酬、企业报销、企业补贴、服务款项、采购货款等自动向用户转账的场景。…

8个Python高效数据分析的技巧

这篇文章介绍了8个使用Python进行数据分析的方法&#xff0c;不仅能够提升运行效率&#xff0c;还能够使代码更加“优美”。 1 一行代码定义List 定义某种列表时&#xff0c;写For 循环过于麻烦&#xff0c;幸运的是&#xff0c;Python有一种内置的方法可以在一行代码中解决…

MDC使用手册精讲

MDC 背景&#xff1a; 线上排查问题时&#xff0c;请求在多个微服务之间进行调用&#xff0c;并发量较大的情况下&#xff0c;想跟踪某一个请求的链路&#xff0c;是需要花费一些时间才能梳理出来&#xff0c;而且还依赖于你的业务字段。而我们需要的是快速定位&#xff0c;快…

SpringSecurity登录时在哪里调用我们自定义的UserDetailsServiceImpl

SpringSecurity登录时在哪里调用我们自定义的UserDetailsServiceImpl 1、请求login方法 2、将用户的用户名和密码封装成一个对象&#xff0c;以便进行后续的认证操作 3、执行认证操作 4、调用providermanager类的authenticate 5.进入这一步就开始跟我们自定义实现的UserDet…

【云计算】云数据中心网络(四):IPv6 网关

云数据中心网络&#xff08;四&#xff09;&#xff1a;IPv6 网关 1.什么是 IPv6 网关2.IPv6 网关设计思路3.IPv6 网关的主要应用场景3.1 IPv6 私网通信3.2 IPv6 互联网通信3.3 IPv6 互联网通信&#xff08;仅主动访问&#xff09; 1.什么是 IPv6 网关 2017 年&#xff0c;中国…

OpenHarmony实战开发-Worker子线程中解压文件。

介绍 本示例介绍在Worker 子线程使用ohos.zlib 提供的zlib.decompressfile接口对沙箱目录中的压缩文件进行解压操作&#xff0c;解压成功后将解压路径返回主线程&#xff0c;获取解压文件列表。 效果图预览 使用说明 1.点击解压按钮&#xff0c;解压test.zip文件&#xff0c…

跟着Datawhale重学数据结构与算法

数据结构和算法之前学过&#xff0c;现在跟着Datawhale重学一下&#xff0c;就当是监督自己学习&#xff0c;重新拾起来养成一个好的习惯&#xff0c;以后可以一直坚持下去。 开源链接&#xff1a;【 教程地址 】【电子网站】 首先&#xff1a; #mermaid-svg-Cdr3rn9fGCVAiKS…

文献速递:深度学习胰腺癌诊断--胰腺癌在CT扫描中通过深度学习检测:一项全国性的基于人群的研究

Title 题目 Pancreatic Cancer Detection on CT Scans with Deep Learning: A Nationwide Population-based Study 胰腺癌在CT扫描中通过深度学习检测&#xff1a;一项全国性的基于人群的研究 01 文献速递介绍 胰腺癌&#xff08;PC&#xff09;的五年生存率是所有癌症中…
最新文章