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对象置为空字符串

相关推荐
Dxy12393102167 小时前
JS DES 加密详解
开发语言·javascript·arcgis
充值内卷7 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
云和数据.ChenGuang8 小时前
深入解析 Python 的 dir():从用法到 CPython 源码实现
开发语言·人工智能·python·langchain
nice_lcj5208 小时前
深入理解 Java 反射:从 Class 对象到方法调用(含性能实测 + 迷你 IOC 实战 + 面试考点)
java·开发语言·后端·面试
樱花树下的数学喵10 小时前
手写简易 STL string|C++ 字符串底层实现
开发语言·c++
AI吃大瓜10 小时前
指针压力表读数3:C/C++实现指针压力表读数(可实时检测)
c++·指针读数·指针压力表·压力表自动读数·压力表读数
-银雾鸢尾-10 小时前
两数之和-C++实现
c++·算法
j7~11 小时前
【动态规划算法专题】动态规划五部曲实战:泰波那契数、三步问题、最小花费爬楼梯
c++·算法·动态规划·数据结构与算法
jimy111 小时前
C++ 报错的 qualifiers 的意思
开发语言·c++
揽星河..11 小时前
【C++】类和对象
c++·算法