C++(22)——类型转换和IO流

1. 类型转换

1. C语言中的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转换,C语言中有两种形式类型转换:

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

  1. 显式类型转换:需要用户自己处理

缺陷:

  1. 隐式类型转换可能出现数据精度丢失等问题

  2. 显式类型转换将所有情况混合在一起,可视性较差,都是以同一种形式书写,难以跟踪错误的转换

2. C++强制类型转换

2.1 static_cast

编译期完成的强制类型转换,编译期检查;做编译器认可的、相对安全的转换

cpp 复制代码
static_cast<目标类型>(原数据)

特点:

多用于非多态类型的转换(静态转换),编译器隐式执行的类型转换都可用,不能用于两个不相关的类型进行转换,不能移除const属性,不会做溢出检查

2.2 reinterpret_cast

直接重新解释内存中的二进制bit,不会进行任何的类型检查、不会转换数值、不会调用构造函数,是最暴力的转换

cpp 复制代码
reinterpret_cast<目标类型>(源对象)

特点:

用于不相关类型之间的转换,编译期完成,无任何运行时检查,风险极高,不能进行数值转换,不能移除const属性

2.3 const_cast

唯一能增加 / 移除 const、volatile 属性的强制性类型转换符

cpp 复制代码
const_cast<目标类型>(表达式)

特点:

编译期完成,无运行时检查,不能进行其他类型转换,不能修改原本定义为const的常量

2.4 dynamic_cast

专门用于多态继承下父子类指针/引用之间向下转换(动态转换)

前置硬性条件:基类必须要有虚函数

cpp 复制代码
dynamic_cast<目标类型>(源对象)

特点:

运行时RTTI检查,对指针转换失败时返回nullptr,对引用转换失败时抛异常 bad_cast

2.5 RTTI(了解)

Run‑Time Type Information------运行时类型信息

程序运行起来之后,能够获取对象的实际类型信息的一套机制

两个核心工具:1. dynamic_cast 向下转型 2. typeid 获取对象的类型信息

2.6 对比

|------------------|-------------------------------|------------|-----------|
| 转换运算符 | 核心用途 | 检查时机 | 必备条件 |
| static_cast | 常规安全转换,数值转换、void * 互转、继承上下转型 | 编译期 | 无 |
| reinterpret_cast | 暴力二进制重解释;指针↔指针、指针↔整数 | 无检查 | 无 |
| const_cast | 增加 / 移除 const、volatile 属性 | 无检查 | 只能指针 / 引用 |
| dynamic_cast | 多态父子类向下安全转型,运行时校验 | 运行时 (RTTI) | 基类要有虚函数 |

2. IO流

1. C语言的输入与输出

C语言种常用的输入输出方式:scanf()和printf()。scanf():从标准输入设备(键盘)读取数据,将其存放在变量中,printf():将指定的文字/字符串输出到标准输出设备(屏幕)。C语言的输入输出都借助了相应的缓冲区来实现

2. 流

流就是数据从一处流向另一处,是对一种有序连续具有方向性的数据的抽象描述

为了实现这种流动,C++定义了I/O标准类库

3. C++IO流

3.1 标准IO流

四大标准流对象

|------|---------|----------|------|----------|
| 对象 | 类型 | 方向 | 默认设备 | 缓冲特性 |
| cin | istream | 输入:外部→程序 | 键盘 | 行缓冲 |
| cout | ostream | 输出:程序→外部 | 显示器 | 行缓冲 |
| cerr | ostream | 错误输出 | 显示器 | 无缓冲,立刻打印 |
| clog | ostream | 日志输出 | 显示器 | 带缓冲 |

流的四种状态标志

  1. good():true → 一切正常,没有出错

  2. eof():true → 读到文件 / 输入末尾(EOF)

  3. fail():true → 逻辑错误,读取失败,例如:读 int 输入字母

  4. bad():true → 致命错误,流已经损坏,不可恢复

运算符

>> 提取运算符:从流对象中拿数据 cin >> a

<< 插入运算符:把数据送入流对象 cout << a

缓冲区

输出的数据不会立刻显示到屏幕,先存放在缓冲区

刷新缓冲区时机:

  1. 遇到换行符endl(endl = \n + 刷新缓冲区)

  2. 缓冲区写满

  3. 程序结束

  4. 手动刷新:cout.flush()

注意点:

  1. 只有把输入缓冲区的数据读取完后,才要求输入新的数据

  2. 输入的数据类型必须与要提取的数据类型一致,否则出错,在流的状态字state中对应位置置1,程序继续

  3. 空格和回车都可以作为数据之间的分隔符,多个数据可以在一行输入也可以分行输入。但是如果是字符型和字符串,则空格(ASCLII码为32)无法使用cin输入,字符串中也不能有空格,回车符也无法读入

  4. cin和cout可以直接输入输出内置类型数据,标准库已将所有内置类型的输入输出重载了,对于自定义类型,需要对 << 和 >> 进行重载

  5. 连续输入时,vs系列编译器下输入 ctrl+z 即结束

3.2 文件IO流

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

  1. 定义一个文件流对象

  2. 使用文件流对象的成员函数打开一个磁盘文件,建立文件流对象和磁盘文件之间的联系

  3. 使用运算符或成员函数对文件进行读写操作

  4. 关闭文件

三个核心类:

|----------|----------|--------------|-----------------------|
| 类名 | 默认模式 | 功能 | 能否新建文件 |
| ifstream | ios::in | 读文件(文件 → 程序) | 不能,文件不存在,打开失败 |
| ofstream | ios::out | 写文件(程序 → 文件) | 能,文件不存在新建,存在清空 |
| fstream | ios::in | 可读可写文件 | ios::out模式时,能,文件不存在新建 |

3.3 内存IO流(字符串流)

内存流所有操作全部发生在内存中,读写目标是内存区的一块缓冲区

底层缓冲区类:stringbuf(继承streambuf)

内存流三种类:

|---------------|------------------------|
| 类 | 用途 |
| istringstream | 只读内存流,从字符串读取数据,分割字符串 |
| ostringstream | 只写内存流,往字符串写入数据,拼接、类型转换 |
| stringstream | 可读 + 可写内存流,内存上既能读又能写 |

本质:

真正存放字节数据的是 stringbuf ,内部封装了一个 std::string 对象

对流做的读写操作,本质就是在操作缓冲区里的 string

注意点:

  1. 多次数据类型转换时,一定要用clear()来清空,才能正确转换

  2. 使用 .str() 让stringstream返回其底层的string对象,也可以使用 .str(" ") 将底层string对象置为空字符串

相关推荐
小范同学_19 分钟前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
geovindu1 小时前
CSharp: 万年历
开发语言·后端·c#·.net
我找到地球的支点啦1 小时前
Matlab系列(009) 一CRC循环冗余校验详解
开发语言·数据结构·算法·matlab·信息与通信
予昊1 小时前
从零实现“在线五子棋对战“:WebSocket 实时通信 + 段位匹配
java·开发语言·网络·websocket
weixin_461408582 小时前
Mybatis-flex小记
java·开发语言·mybatis
青梅味猪大肠3 小时前
【深入浅出C++】为什么虚表指针可以解决菱形继承
开发语言·c++
潘潘的嵌入式日记3 小时前
I²C 从机接收总被覆盖?双缓冲要在 STOP 时交接
c语言·开发语言·单片机
Lhan.zzZ4 小时前
QML 组件库:VS2022 + Qt 静态库方案
开发语言·c++·qt·visual studio
敲代码的嘎仔4 小时前
28届后端开发-海康威视日常实习一面(已OC)
java·开发语言·后端·面试·海康威视·实习·大厂