1. 类型转换
1. C语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转换,C语言中有两种形式类型转换:
1.隐式类型转换:编译器在编译阶段自动进行,能转就转,不能转就编译失败
- 显式类型转换:需要用户自己处理
缺陷:
-
隐式类型转换可能出现数据精度丢失等问题
-
显式类型转换将所有情况混合在一起,可视性较差,都是以同一种形式书写,难以跟踪错误的转换
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 | 日志输出 | 显示器 | 带缓冲 |
流的四种状态标志
-
good():true → 一切正常,没有出错
-
eof():true → 读到文件 / 输入末尾(EOF)
-
fail():true → 逻辑错误,读取失败,例如:读 int 输入字母
-
bad():true → 致命错误,流已经损坏,不可恢复
运算符
>> 提取运算符:从流对象中拿数据 cin >> a
<< 插入运算符:把数据送入流对象 cout << a
缓冲区
输出的数据不会立刻显示到屏幕,先存放在缓冲区
刷新缓冲区时机:
-
遇到换行符endl(endl = \n + 刷新缓冲区)
-
缓冲区写满
-
程序结束
-
手动刷新:cout.flush()
注意点:
-
只有把输入缓冲区的数据读取完后,才要求输入新的数据
-
输入的数据类型必须与要提取的数据类型一致,否则出错,在流的状态字state中对应位置置1,程序继续
-
空格和回车都可以作为数据之间的分隔符,多个数据可以在一行输入也可以分行输入。但是如果是字符型和字符串,则空格(ASCLII码为32)无法使用cin输入,字符串中也不能有空格,回车符也无法读入
-
cin和cout可以直接输入输出内置类型数据,标准库已将所有内置类型的输入输出重载了,对于自定义类型,需要对 << 和 >> 进行重载
-
连续输入时,vs系列编译器下输入 ctrl+z 即结束
3.2 文件IO流
C++根据文件内容的数据格式分为二进制文件和文本文件,采用文件流对象操作文件的步骤:
-
定义一个文件流对象
-
使用文件流对象的成员函数打开一个磁盘文件,建立文件流对象和磁盘文件之间的联系
-
使用运算符或成员函数对文件进行读写操作
-
关闭文件
三个核心类:
|----------|----------|--------------|-----------------------|
| 类名 | 默认模式 | 功能 | 能否新建文件 |
| ifstream | ios::in | 读文件(文件 → 程序) | 不能,文件不存在,打开失败 |
| ofstream | ios::out | 写文件(程序 → 文件) | 能,文件不存在新建,存在清空 |
| fstream | ios::in | 可读可写文件 | ios::out模式时,能,文件不存在新建 |
3.3 内存IO流(字符串流)
内存流所有操作全部发生在内存中,读写目标是内存区的一块缓冲区
底层缓冲区类:stringbuf(继承streambuf)
内存流三种类:
|---------------|------------------------|
| 类 | 用途 |
| istringstream | 只读内存流,从字符串读取数据,分割字符串 |
| ostringstream | 只写内存流,往字符串写入数据,拼接、类型转换 |
| stringstream | 可读 + 可写内存流,内存上既能读又能写 |
本质:
真正存放字节数据的是 stringbuf ,内部封装了一个 std::string 对象
对流做的读写操作,本质就是在操作缓冲区里的 string
注意点:
-
多次数据类型转换时,一定要用clear()来清空,才能正确转换
-
使用 .str() 让stringstream返回其底层的string对象,也可以使用 .str(" ") 将底层string对象置为空字符串