Awesome
C++从0到1案例学习
目录介绍
- 01.第一天:基础语法
- 1.1 第一个C++程序
- 1.2 修饰符和标识符
- 1.3 数据类型
- 1.4 变量和常量
- 1.5 字符串使用
- 02.第二天:运算符和表达式
- 2.1 运算符
- 2.2 表达式
- 03.第三天:判断和循环
- 3.1 条件判断
- 3.2 循环语句
- 3.3 判断和循环练习题
- 04.第四天:函数实践
- 4.1 函数的定义
- 4.2 函数返回值和参数
- 4.3 函数的调用
- 4.4 函数模版
- 05.第五天:指针和引用
- 5.1 指针和引用
- 5.2 指针详细介绍
- 5.3 指针与安全
- 5.4 函数与引用
- 06.第六天:数组和容器
- 6.1 数组介绍使用
- 6.2 序列容器
- 6.3 关联容器
- 6.4 无序容器
- 07.第七天:IO输入和输出
- 7.1 基本的输入输出
- 7.2 文件操作实践
- 7.3 IO综合案例
- 08.第八天:结构和类
- 8.1 数据结构
- 8.2 类和对象
- 8.3 类成员
- 8.4 命名空间
- 09.第九天:继承和派生
- 9.1 继承
- 9.2 重载运算符和重载函数
- 9.3 多态
- 9.4 抽象类和数据抽象
- 10.第十天:多线程和并发
- 10.1 线程实践
- 10.2 多线程
- 10.3 何为并发
- 11.第十一天:线程安全锁
- 11.1 理解同步机制
- 11.2 互斥锁mutex
- 11.3 条件变量
- 11.4 其他场景锁
- 12.第十二天:内存分配堆和栈
- 12.1 动态内存
- 12.2 智能内存管理
- 13.第十三天:异常处理
- 13.1 异常声明和处理
- 13.2 异常体系说明
- 14.第十四天:STL标准模板库
- 14.1 C++ 标准模板库
- 14.2 STL 算法
- 14.3 STL 迭代器
- 14.4 STL 适配器
- 14.5 STL 函数对象
- 15.第十五天:高级教程
- 15.1 预处理器
- 15.2 信号处理
- 16.第十六天:程序调试
- 17.第十七天:网络通信
- 18.第十八天:综合案例
01.第一天:基础语法
1.1 第一个C++程序
- 1.1.1 C++简单介绍
- 1.1.1.1 面向对象程序设计,完全支持面向对象的程序设计,包括面向对象开发的四大特性:封装,继承,多台,抽象
- 1.1.1.2 标准库,由3个部分组成。核心语言,c++标准库,标准模版库STL
- 1.1.1.3 C++ 的使用场景,在许多行业和领域都有广泛应用,包括:游戏,嵌入式,图形图像等
- 1.1.1.4 C++ 编译器编译,程序 g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本,链接时它自动使用 C++ 标准库而不用 C 标准库。
- 1.1.2 C++基本语法
- 1.1.2.1 基本语法介绍,主要看一下类,对象,方法,变量等
- 1.1.2.2 C++ 程序结构,学习和练习hello world案例
- 1.1.2.3 编译 & 执行 C++ 程序,如何把源代码保存在一个文件中,以及如何编译并运行它
- 1.1.2.4 C++ 中的分号 & 语句块,分号是语句结束符。每个语句必须以分号结束。它表明一个逻辑实体的结束。
- 1.1.3 C++ 注释
- 1.3.1 C++ 注释分类,C++ 支持单行注释和多行注释。注释中的所有字符会被 C++ 编译器忽略。
1.2 修饰符和标识符
- 1.2.1 修饰符
- 1.2.1.1 什么是修饰符,修饰符(modifiers)是用于修改基本数据类型的关键字。它们可以改变数据类型的行为、范围或存储方式。
- 1.2.1.2 const:用于声明常量,表示变量的值在初始化后不能被修改。
- 1.2.1.3 volatile:用于声明易变变量,表示变量的值可能会在未知的时间被改变,通常用于多线程或硬件相关的编程。
- 1.2.1.4 signed 和 unsigned:用于整数类型,指定变量是否可以表示负数。
- 1.2.1.5 short 和 long:用于整数类型,指定变量的范围。short表示短整数,long表示长整数
- 1.2.1.6 static:用于变量和函数,表示变量在整个程序执行期间保持其值,函数在当前文件中可见。
- 1.2.1.7 extern:用于变量和函数,表示变量或函数在其他文件中定义或声明。
- 1.2.2 标志符
- 1.2.2.1 什么是标志符,C++ 标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。
- 1.2.2.2 有效标志符,一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)。
- 1.2.2.3 无效标志符,C++ 标识符内不允许出现标点字符,比如 @、& 和 %。C++ 是区分大小写的编程语言。
1.3 数据类型
- 1.3.1 基本的内置类型
- 1.3.1.1 bool,布尔类型,bool是一种布尔类型,用于表示逻辑值。bool类型只有两个可能的值:true和false。
- 1.3.1.2 char,字符型,用于表示单个字符。char类型占用一个字节的内存空间,可以表示256个不同的字符,包括字母、数字、标点符号和特殊字符。
- 1.3.1.3 int,整型,用于表示整数。int类型通常占用4个字节的内存空间(32位系统),可以表示范围内的整数值。
- 1.3.1.4 float,浮点型,用于表示单精度浮点数。float类型通常占用4个字节的内存空间,可以表示小数或具有较大范围的数值。
- 1.3.1.5 double,双浮点型,用于表示双精度浮点数。double类型通常占用8个字节的内存空间,可以表示更大范围和更高精度的浮点数。
- 1.3.1.6 void,无类型,特殊的数据类型,表示无类型。void类型用于表示不返回任何值的函数、指针或函数参数。
- 1.3.1.7 wchar_t,宽字符型,宽字符是一种可以表示更广泛字符集的字符类型,通常用于处理多语言、国际化和Unicode字符。
- 1.3.2 多类型修饰符
- 2.2.1 signed,有符号类型是一种整数类型,可以表示正数、负数和零。有符号类型使用signed关键字进行声明。
- 2.2.2 unsigned,无符号类型是一种整数类型,它只能表示非负整数值。无符号类型使用unsigned关键字进行声明。
- 2.2.3 short,short是一种有符号短整数类型,通常为16位。
- 2.2.4 long,有符号长整数类型,通常为32位或64位,范围取决于编译器和平台。
- 1.3.3 其他一些类型
- 2.3.1 size_t,是一种无符号整数类型,用于表示对象的大小或数组的索引。它是C++标准库中定义的类型,通常用于表示内存大小、数组长度和对象的大小。
- 2.3.2 uint8_t,uint8_t是一种固定宽度的无符号整数类型,用于表示8位(1字节)的无符号整数值。
- 2.3.3 enum,枚举类型(enumeration)是C++中的一种派生数据类型,它是由用户定义的若干枚举常量的集合。
- 1.3.4 typedef 声明
- 2.4.1 typedef声明,使用 typedef 为一个已有的类型取一个新的名字。
- 1.3.5 类型转换
- 2.5.1 静态转换(Static Cast),static_cast静态转换是将一种数据类型的值强制转换为另一种数据类型的值。
- 2.5.2 动态转换(Dynamic Cast),dynamic_cast动态转换通常用于将一个基类指针或引用转换为派生类指针或引用。
- 2.5.3 常量转换(Const Cast),const_cast常量转换用于将 const 类型的对象转换为非 const 类型的对象。
- 2.5.4 重新解释转换(Reinterpret Cast),reinterpret_cast重新解释转换将一个数据类型的值重新解释为另一个数据类型的值,通常用于在不同的数据类型之间进行转换。
- 1.3.8 做一些练习
-
2.8.1 将char转化为uint8_t,由于char类型可以是有符号或无符号的,转换为uint8_t类型可以确保将其视为无符号8位整数。
-
2.8.2 将string转化为uint8_t,将std::string转换为uint8_t类型需要进行逐个字符的转换。
-
1.3 变量和常量
- 3.1 变量类型
- 3.1.1 变量类型介绍,多种变量类型可用于存储不同种类的数据。基本数据类型,也允许定义比如枚举、指针、数组、引用、数据结构、类等等
- 3.1.2 C++中的变量定义,变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。
- 3.1.3 C++中的变量声明,变量声明向编译器保证变量以给定的类型和名称存在
- 3.1.4 C++中左值和右值,左值可以出现在赋值号的左边或右边。右值是不能对其进行赋值的表达式
- 3.2 变量作用域
- 3.2.1 作用域介绍,一般来说有三个地方可以定义变量,作用域是程序的一个区域,变量的作用域可以分为4种
- 3.2.2 局部变量,在函数或一个代码块内部声明的变量,称为局部变量。它们只能被函数内部或者代码块内部的语句使用。
- 3.2.3 全局变量,在所有函数外部定义的变量(通常是在程序的头部),称为全局变量。全局变量的值在程序的整个生命周期内都是有效的。
- 3.2.4 类作用域,在类内部声明的变量具有类作用域,它们可以被类的所有成员函数访问。类作用域变量的生命周期与类的生命周期相同。
- 3.2.5 块作用域,在代码块内部声明的变量具有块作用域,它们只能在代码块内部访问。块作用域变量在代码块每次被执行时被创建,在代码块执行完后被销毁。
- 3.3 常量
- 3.3.1 整数常量,整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。
- 3.3.2 浮点常量,浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
- 3.3.3 布尔常量,布尔常量共有两个,它们都是标准的 C++ 关键字:true 值代表真。 false 值代表假。
- 3.3.4 字符常量,字符常量是括在单引号中。如果常量以 L(仅当大写时)开头,则表示它是一个宽字符常量(例如 L'x')
- 3.3.5 字符串常量,字符串字面值或常量是括在双引号 "" 中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
- 3.3.6 定义常量,在 C++ 中,有两种简单的定义常量的方式:使用 #define 预处理器。使用 const 关键字。
1.5 字符串使用
- 1.5.1 字符串介绍和使用
- 1.5.1.1 C 风格字符串,C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null 字符 \0 终止的一维字符数组。
- 1.5.1.2 函数处理字符串,C++ 中有大量的函数用来操作以 null 结尾的字符串,strcpy复制,strlen返回长度,strcmp比较是否相同等等
- 1.5.1.3 C++中String类,std::string是C++标准库中提供的字符串类,它提供了许多方便的方法和操作符来处理字符串。它方便地进行字符串的操作和管理,而无需手动处理内存分配和释放。
- 1.5.1.4 输入字符串,cin.getline() 是在输入一段字符完成后开始读取数据。
- 1.5.2 字符串转化
- 1.5.2.1 字符串转化为数组
- 1.5.2.2 字符串转化为vector向量
- 1.5.2.3 将基础类型数据转为字符串
02.第二天:运算符和表达式
2.1 运算符
- 2.1.1 算术运算符
- 2.1.2 关系运算符
- 2.1.3 逻辑运算符
- 2.1.4 位运算符
- 2.1.5 赋值运算符
- 2.1.6 杂项运算符
- 2.1.7 运算符优先级
2.2 表达式
2.17 运算符和表达式练习题
3.5.1 求1~10的累加和 56 3.5.2 求一个整数任意次方后的最后三位数 56 3.5.3 婚礼上的谎言 57 3.5.4 阿姆斯特朗数 58 3.5.5 满足abcd=(ab+cd) 2的数 59 3.5.6 最大公约数及最小公倍数 59
03.第三天:判断和循环
3.1 条件判断
- 3.1.1 条件判断语句
- 3.1.1.1 if语句
- 3.1.1.2 if...else语句
- 3.1.1.3 嵌套的if-else语句
- 3.1.1.4 使用条件运算符进行判断
- 3.1.1.5 switch判断语句
3.2 循环语句
- 3.2.1 循环语句
- 3.2.1.1 while循环语句
- 3.2.1.2 do...while循环
- 3.2.1.3 while与do...while比较
- 3.2.1.4 for循环语句
- 3.2.2 循环控制
- 3.2.2.1 控制循环的变量
- 3.2.2.2 break语句
- 3.2.2.3 continue语句
- 3.2.2.4 goto语句
3.3 判断和循环练习题
- 3.3.1 判断和循环练习题
- 3.3.1.1 小写字母转大写
- 3.3.1.2 百鸡百钱问题
- 3.3.1.3 判断三角形类型
- 3.3.1.4 简单计算器
- 3.3.1.5 求总数问题
- 3.3.1.6 加油站加油
- 3.3.1.7 灯塔数量
- 3.3.1.8 尼科彻斯定理
04.第六天:函数实践
4.1 函数的定义
- 4.1.1 什么是函数
- 4.1.1.1 无参函数
- 4.1.1.2 有参函数
- 4.1.1.3 空函数
- 4.1.2 内部和外部函数
- 4.1.2.1 内部函数
- 4.1.2.2 外部函数
4.2 函数返回值和参数
- 4.2.1 返回语句
- 4.2.1.1 从函数返回
- 4.2.1.2 返回值
- 4.2.2 函数参数
- 4.2.2.1 形式参数与实际参数
- 4.2.2.2 数组作函数参数
- 4.2.2.3 main参数
4.3 函数的调用
- 4.3.1 函数调用
- 4.3.1.1 函数调用方式
- 4.3.1.2 嵌套调用
- 4.3.1.3 递归调用
4.4 函数模版
- 4.3.1 函数模版
- 4.3.1.1 什么是函数模版,允许我们编写通用的函数,可以用于多种数据类型而不需要为每种数据类型编写不同的函数。
- 4.3.1.2 函数模板运用,通过使用函数模板,我们可以编写通用的代码,提高代码的重用性和灵活性,同时减少代码的冗余。
05.第五天:指针和引用
- C++ 中常量引用、指向常量的指针、常量指针的区别
5.1 指针和引用
- 5.1.1 指针的基础介绍
- 5.1.1.1 什么是指针,通过指针,可以简化一些 C++ 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。
- 5.1.1.2 指针运算符和取地址运算符,每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。
- 5.1.1.3 变量与指针,指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。用来声明指针的星号 *,星号是用来指定一个变量是指针。
- 5.1.1.4 指针使用,定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。
- 5.1.1.5 指针类型强制转换,指针的值以及指针指向地址的值对应为数据的地址和该地址内存储数据的值,将指针转换类型后继续操作应注意大小端。
- 5.1.1.6 Null 指针,在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
- 5.1.1.7 指针 vs 数组,指针和数组是密切相关的。事实上,指针和数组在很多情况下是可以互换的。
- 5.1.1.8 指针数组,
- 5.1.2 引用基础介绍
- 5.1.2.1 引用的概述,引用变量是一个别名,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
- 5.1.2.2 C++ 中创建引用,& 读作引用。变量名称是变量附属在内存位置中的标签,您可以把引用当成是变量附属在内存位置中的第二个标签。
- 5.1.2.3 把引用作为参数,C++之所以增加引用类型, 主要是把它作为函数参数,以扩充函数传递数据的功能。
- 5.1.2.4 把引用作为返回值,当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。
- 5.1.2.5 引用 vs 指针,引用必须在创建时被初始化,指针可以在任何时间被初始化。一旦引用被初始化为一个对象,就不能被指向到另一个对象,指针可以在任何时候指向到另一个对象。
5.2 指针详细介绍
- 5.2.1 指针的算数运算
- 5.2.1.1 指针的算术运算介绍,指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。
- 5.2.1.2 递增一个指针,在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,因为数组是一个常量指针。
- 5.2.1.3 递减一个指针,对指针进行递减运算,即把值减去其数据类型的字节数
- 5.2.1.4 指针的比较,指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
- 5.2.2 指针和函数
- 5.2.2.1 指向指针的指针,指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。
- 5.2.2.2 传递指针给函数,通过引用或地址传递参数,使传递的参数在调用函数中被改变。
- 5.2.2.3 从函数返回指针,C++ 允许函数返回指针到局部变量、静态变量和动态内存分配。C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static变量。
5.3 指针与安全
- 5.3.1 指针与安全基础
- 5.3.1.1 内存的分配方式
- 5.3.1.2 内存安全
5.4 函数与引用
- 5.4.1 函数与引用
- 5.4.1.1 左值与右值
- 5.4.1.2 右值引用
- 5.4.1.3 使用引用传递参数
- 5.4.1.4 指针与引用
- 5.4.1.5 右值引用传递参数
5.5 指针和引用练习题
- 5.5.1 基础练习题
- 5.5.1.1 使用左值引用实现整数排序
- 5.5.1.2 查找成绩不及格的学生
- 5.5.1.3 指针实现冒泡排序
- 5.5.1.4 使用指针插入元素
- 5.5.1.5 使用指针的指针输出字符串
- 5.5.1.6 为二维数组动态分配内存并释放
- 5.5.1.7 使用右值引用转换二进制为十进制
06.第四天:数组和容器
6.1 数组介绍使用
- 6.1.1 数组基础使用
- 6.1.1.1 声明数组,在 C++ 中要声明一个数组,需要指定元素的类型和元素的数量
- 6.1.1.2 初始化数组,可以逐个初始化数组,也可以使用一个初始化语句
- 6.1.1.3 访问数组元素,数组元素可以通过数组名称加索引进行访问。元素的索引是放在方括号内,跟在数组名称的后边。
- 6.1.2 C++中数组详解
- 6.1.2.1 多维数组,C++ 支持多维数组。多维数组最简单的形式是二维数组。
- 6.1.2.2 指向数组的指针,您可以通过指定不带索引的数组名称来生成一个指向数组中第一个元素的指针。
- 6.1.2.3 传递数组给函数,您可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。
- 6.1.2.4 从函数返回数组,C++ 允许从函数返回数组。
6.2 序列容器
- 6.2.1 std::vector动态数组
- 6.2.1.1 为什么有Vector,C++ 中的 vector 是一种序列容器,它允许你在运行时动态地插入和删除元素。基于数组的数据结构,但它可以自动管理内存
- 6.2.1.2 Vector基础函数,添加元素,访问元素,获取大小,迭代访问,删除元素,清空 Vector
- 6.2.1.3 Vector综合实践,创建了一个整数向量,添加了几个元素,然后输出了向量内容、元素的访问、向量的大小等信息,并输出删除元素后的向量。
- 6.2.2 std::deque双端队列
- 6.2.3 std::list:链表
6.3 关联容器
- 6.3.1 std::set:集合
- 6.3.2 std::multiset:多重集合
- 6.3.3 std::map:映射
- 6.3.4 std::multimap:多重映射
6.4 无序容器
- 6.4.1 std::unordered_set:无序集合
- 6.4.2 std::unordered_multiset:无序多重集合
- 6.4.3 std::unordered_map:无序映射
- 6.4.4 std::unordered_multimap:无序多重映射
6.3 容器使用介绍
- 6.3.1 容器介绍
- 6.3.1.0 什么是容器,容器(containers)是用于存储和管理一组数据元素的类模板。C++标准库提供了多种容器,每种容器都有不同的特性和适用场景。
- 6.3.1.1 std::list:双向链表。支持高效的插入和删除操作。
- 6.3.1.2 std::deque:双端队列,类似于动态数组,支持在两端进行插入和删除操作。
- 6.3.1.3 std::set:有序集合,存储唯一的元素,并按照一定的排序规则进行排序。
- 6.3.1.4 std::map:关联容器,存储键值对,按照键的顺序进行排序。
- 6.3.1.5 std::unordered_set:无序集合,存储唯一的元素,使用哈希表实现。
- 6.3.1.6 std::unordered_map:无序关联容器,存储键值对,使用哈希表实现。
- 6.3.1.7 std::stack
- 6.3.1.8 std::queue
- 6.3.1.9 std::priority_queue
07.第七天:IO输入和输出
7.1 基本的输入输出
- 7.1.1 IO输入输出
- 7.1.1.1 输入输出介绍,C++ 的 I/O 发生在流中,流是字节序列。如果字节流是从设备流向内存,这叫做输入操作。如果字节流是从内存流向设备,这叫做输出操作。
- 7.1.1.2 I/O 库头文件,<iostream>分别对应于标准输入流、标准输出流。<iomanip>声明对执行标准化 I/O 有用的服务。<fstream>为用户控制的文件处理声明服务。
- 7.1.1.3 标准输出流(cout),预定义的对象 cout 是 iostream 类的一个实例。cout 对象"连接"到标准输出设备。cout 是与流插入运算符 << 结合使用的。
- 7.1.1.4 标准输入流(cin),预定义的对象 cin 是 iostream 类的一个实例。cin 对象附属到标准输入设备,通常是键盘。cin 是与流提取运算符 >> 结合使用的。
- 7.1.1.5 标准错误流(cerr),预定义的对象 cerr 是 iostream 类的一个实例。cerr 对象附属到标准输出设备,通常也是显示屏
- 7.1.1.6 标准日志流(clog),预定义的对象 clog 是 iostream 类的一个实例。clog 对象附属到标准输出设备,通常也是显示屏
7.2 文件操作实践
- 7.2.1 文件打开
- 7.2.1.1 打开方式,ofstream 和 fstream 对象都可以用来打开文件进行写操作,如果只需要打开文件进行读操作,则使用 ifstream 对象。
- 7.2.1.2 默认打开模式,open() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。用这个方法打开文件。
- 7.2.1.3 打开文件同时创建文件,
- 7.2.2 文件的读写
- 7.2.2.1 文件流说明, C++ 中另一个标准库 fstream,它定义了三个新的数据类型:ofstream,ifstream,fstream
- 7.2.2.2 键盘输入写文本文件,使用fstream库将键盘输入的内容写入文件。使用std::getline()函数从键盘读取一行输入,并将输入内容使用<<操作符写入文件。
- 7.2.2.3 创建文件写内容,创建了一个ofstream对象file,并指定要写入的文件名为"yc.txt",可以使用<<操作符将文本内容写入文件。
- 7.2.2.4 读取文本文件,可以使用fstream库来读取文件内容,使用流提取运算符( >> )从文件读取信息,就像使用该运算符从键盘输入信息一样。
- 7.2.2.5 二进制文件的读/写,<iostream>和<fstream>头文件,分别用于输入输出和文件操作。对二进制文件分别进行写入和读取。
- 7.2.2.6 实现文件复制
- 7.2.2.7 关闭文件,close() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。写读写文件操作完成后,关闭流对象。
- 7.2.3 文件指针移动操作
- 7.2.3.1 文件错误与状态,文件错误和状态可以通过文件流对象的状态标志来表示。std::fstream类中定义了一些成员函数和状态标志,用于检测和处理文件错误和状态。
- 7.2.3.2 文件的追加,可以使用文件流对象的std::ofstream类来实现文件的追加操作。要实现文件的追加,需要在打开文件时指定追加模式。
- 7.2.3.3 文件结尾的判断,可以使用文件流对象的eof()函数来判断文件是否已经到达结尾。
- 7.2.3.4 在指定位置读/写文件,可以使用文件流对象的seekg()和seekp()函数来在指定位置进行文件的读取和写入操作。
7.3 IO综合案例
- 7.3.1 IO流实践
- 7.3.1.1 合并两个文件信息
- 7.3.1.2 文件复制
- 7.3.1.3 文件加密
- 7.3.1.4 使用销毁的手段保护文件内容
- 7.3.1.5 在文件中查找关键词出现的次数
08.第八天:结构和类
8.1 数据结构
- 8.1.1 struct结构类型
- 8.1.1.1 为何设计结构,结构是 C++ 中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
- 8.1.1.2 定义结构,使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型
- 8.1.1.3 访问结构成员,使用成员访问运算符(.)。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个句号。
- 8.1.2 struct结构实践
- 8.1.2.1 结构作为函数参数,把结构作为函数参数,传参方式与其他类型的变量或指针类似。
- 8.1.2.2 指向结构的指针,可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似:struct Books *struct_pointer;
- 8.1.2.3 typedef结构方式,可以为创建的类型取一个"别名"。
- 8.1.2.4 . 与 -> 运算符,访问结构的成员时使用点运算符,而通过指针访问结构的成员时则使用箭头运算符。
- 8.1.2.5 结构作为函数返回值,可以在函数中定义返回值为结构,对函数封装
8.2 类和对象
- 8.2.1 类声明和实现
- 8.2.1.1 类概述,C++ 支持面向对象程序设计。类用于指定对象的形式,是一种用户自定义的数据类型,它是一种封装了数据和函数的组合。
- 8.2.1.2 类的声明与定义,定义一个类需要使用关键字 class,然后指定类的名称,并类的主体是包含在一对花括号中,主体包含类的成员变量和成员函数。
- 8.2.1.3 类的实现,定义了一个名为Person的类。它有两个私有成员变量:name和age。我们使用构造函数来初始化这些成员变量。
- 8.2.1.4 对象的声明,类提供了对象的蓝图,对象是根据类来创建的。声明类的对象,就像声明基本类型的变量一样。
- 8.2.2 构造函数
- 8.2.2.1 构造函数概述,类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
- 8.2.2.2 带参数的构造函数,默认的构造函数没有任何参数,但如果需要,构造函数也可以带有参数。这样在创建对象时就会给对象赋初始值
- 8.2.2.3 析构函数,类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
- 8.2.2.4 拷贝构造函数,拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。
- 8.2.3 类访问修饰符
- 8.2.3.1 类访问修饰符介绍,类成员的访问限制是通过在类主体内部对各个区域标记 public、private、protected 来指定的。
- 8.2.3.2 访问修饰符继承中的特点,有public, protected, private三种继承方式,它们相应地改变了基类成员的访问属性。
- 8.2.4 类模版
- 8.2.4.1 什么是类模版,类模板允许我们定义一个通用的类模板,其中的某些成员可以使用泛型类型,从而使得类可以适用于多种不同的数据类型。
- 8.2.4.2 类模版设计和实践,通过使用类模板,我们可以在实例化时指定具体的类型,从而创建特定类型的对象。
8.3 类成员
- 8.3.1 访问类的属性
- 8.3.1.1 访问类成员,类的对象的公共数据成员可以使用直接成员访问运算符 . 来访问。
- 8.3.1.2 成员函数,成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义。
- 8.3.1.3 内联成员函数,在类定义中定义的成员函数把函数声明为内联的,即便没有使用 inline 标识符。
- 8.3.1.4 友元函数,类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。
- 8.3.1.5 静态类成员,声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。
- 8.3.2 类成员其他
- 8.3.2.1 隐藏的this指针,this是一个隐藏的指针,可以在类的成员函数中使用,它可以用来指向调用对象。
- 8.3.2.2 指向类的指针,指向 C++ 类的指针与指向结构的指针类似,访问指向类的指针的成员,需要使用成员访问运算符 ->,就像访问指向结构的指针一样。
- 8.3.2.2 嵌套类
- 8.3.2.3 局部类
8.4 命名空间
- 8.4.1 命名空间实现
- 8.4.1.1 命名空间场景介绍,引入了命名空间这个概念,它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文。
- 8.4.1.2 定义命名空间,命名空间的定义使用关键字 namespace,后跟命名空间的名称。为了调用带有命名空间的函数或变量,需要在前面加上命名空间的名称
- 8.4.1.3 using 指令,可以使用 using namespace 指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。
- 8.4.1.4 不连续的命名空间,命名空间可以定义在几个不同的部分中,因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。
- 8.4.1.5 嵌套的命名空间,命名空间可以嵌套,可以在一个命名空间中定义另一个命名空间。可以通过使用 :: 运算符来访问嵌套的命名空间中的成员
09.第九天:继承和派生
9.1 继承
- 9.1.1 继承的特性
- 9.1.1.1 类的继承,继承允许依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易,达到了重用代码功能和提高执行效率的效果。
- 9.1.1.2 继承后可访问性,继承后的可访问性是指派生类(子类)对基类(父类)成员的访问权限(public,protected,private)。
- 9.1.1.3 构造函数访问顺序,构造函数的调用顺序是从最基类开始,逐级向下,直到最终派生类。
- 9.1.1.4 子类隐藏父类的成员函数,子类可以通过定义与父类同名的成员函数来隐藏父类的成员函数。
- 9.1.2 多重继承
- 9.1.2.1 多重继承定义,多继承即一个子类可以有多个父类,它继承了多个父类的特性。
- 9.1.2.2 多重继承二义性,多重继承中,当派生类从多个基类中继承相同的成员函数或成员变量时,可能会导致二义性问题。编译器无法确定应该使用哪个基类的成员,从而导致编译错误。
- 9.1.2.3 多重继承的构造顺序,多重继承的构造函数的调用顺序是按照派生类中基类的声明顺序来确定的
9.2 重载运算符和重载函数
- 9.2.1 函数重载
- 9.2.1.1 C++ 中的函数重载,在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。
- 9.2.2 运算符重载
- 9.2.2.1 重载运算符的必要性
- 9.2.2.2 重载运算符的形式与规则
- 9.2.2.3 重载运算符的运算
- 9.2.2.4 转换运算符
- https://www.runoob.com/cplusplus/cpp-overloading.html
9.3 多态
- 9.3.1 多态实践
- 9.3.1.1 什么是多态,多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
- 9.3.1.2 虚函数概述,虚函数 是在基类中使用关键字 virtual 声明的函数。告诉编译器不要静态链接到该函数。
- 9.3.1.3 利用虚函数实现动态绑定,也就是在运行时根据对象的实际类型来调用相应的函数实现。
- 9.3.1.4 虚继承,虚继承是一种特殊的继承方式,用于解决多继承中的菱形继承问题和冗余基类问题。虚继承可以确保在多继承中只有一个共享基类的实例。
9.4 抽象类和数据抽象
- 9.4.1 抽象类
- 9.4.1.1 什么是抽象类,抽象类是一种不能被实例化的类,它的目的是作为其他类的基类,提供接口和规范。C++ 接口是使用抽象类来实现的
- 9.4.1.2 抽象类的实例,定义抽象类的派生类,然后实现抽象类中的纯虚函数,最后创建派生类对象
- 9.4.1.3 实现抽象类中的成员函数,实现抽象类中的成员函数,需要在抽象类中声明纯虚函数。纯虚函数是通过在函数声明后面加上= 0来定义的
- 9.4.2 数据抽象
- 9.4.2.1 什么是数据抽象,数据抽象是指,只向外界提供关键信息,并隐藏其后台的实现细节,即只表现必要的信息而不呈现细节。
- 9.4.2.2 访问标签强制抽象,我们使用访问标签来定义类的抽象接口。一个类可以包含零个或多个访问标签
- 9.4.2.3 数据抽象的实例,通过数据抽象,我们可以将类的实现细节与接口分离,简化了类的使用和理解。
- 9.4.2.5 数据抽象的好处,数据抽象提供了一种将类的实现细节隐藏起来的机制,通过封装和隐藏,提高了代码的安全性、可维护性和可扩展性。
10.第十天:多线程和并发
10.1 线程实践
- 10.1.1 pthread线程基础
- 10.1.1.1 创建线程,使用pthread_create 创建一个新的线程,并让它可执行。
- 10.1.1.2 终止线程,pthread_exit 用于显式地退出一个线程。该函数是在线程完成工作后无需继续存在时被调用。
- 10.1.1.3 取消线程,使用pthread_cancel函数向指定线程发送取消请求,使其终止执行。
- 10.1.1.4 向线程传递参数,通过结构传递多个参数。您可以在线程回调中传递任意的数据类型,因为它指向 void。
- 10.1.1.5 连接线程,可以使用pthread_join函数来等待一个线程的结束并连接(join)它。
- 10.1.1.6 分离线程,可以使用pthread_detach函数将一个线程设置为分离状态(detached)。分离状态的线程在结束时会自动释放其资源
- 10.1.2 std::thread线程
- 10.1.2.1 std::thread 构造函数,默认构造函数,创建一个空的 std::thread 执行对象,初始化,拷贝构造函数用例
- 10.1.2.2 std::thread 赋值操作,Move 赋值操作,拷贝赋值操作
- 10.1.2.3 std::thread 获取线程id,get_id: 获取线程 ID,返回一个类型为 std::thread::id 的对象。
- 10.1.2.4 std::thread joinable,检查线程是否可被 join。
- 10.1.2.5 std::thread detach分离,将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以单独进行。
- 10.1.2.6 std::thread swap交换线程
- 10.1.2.7 native_handle函数
- 10.1.2.8 std::this_thread 命名空间
- 10.1.2.9 std::thread 休眠函数
11.第十一天:线程安全锁
11.1 理解同步机制
- 11.1.1 理解线程同步机制
- 11.1.1.1 为何需要线程安全锁
- 11.1.1.2 什么是线程安全锁
11.2 互斥锁mutex
11.3 条件变量
11.4 其他场景锁
12.第十二天:内存分配堆和栈
12.1 动态内存
- 12.1.1 动态内存基础
- 12.1.1.1 什么是动态内存,无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。
- 12.1.1.2 new 和 delete 运算符,new运算符用于在运行时动态分配内存,delete运算符用于释放通过new运算符分配的内存。
- 12.1.1.3 new 和 malloc区别,new运算符在C++中更常用,而malloc函数在C++中仍然可以使用,特别是在与C代码进行交互时。
- 12.1.1.4 对象的动态内存分配,可以使用动态内存分配来创建对象。动态内存分配允许在运行时根据需要分配和释放内存。
- 12.1.2 数组动态内存
- 12.1.2.1 一维数组的动态内存分配,可以使用动态内存分配来创建一维数组。动态内存分配允许在运行时根据需要分配和释放内存。
- 12.1.2.2 二维数组的动态内存分配,可以使用动态内存分配来创建二维数组。动态内存分配允许在运行时根据需要分配和释放内存。
12.2 智能内存管理
- 12.2.1 智能指针内存管理
- 12.2.1.1 std::shared_ptr,是C++11中引入的智能指针类,用于管理动态分配的内存。它提供了自动的内存管理和资源释放
- 12.2.1.2 std::unique_ptr,与std::shared_ptr不同,std::unique_ptr不允许多个指针共享同一个对象的所有权,它是独占所有权的智能指针。
13.第十三天:异常处理
13.1 异常声明和处理
- 13.1.1 异常简单使用
- 13.1.1.1 异常的介绍,异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw。
- 13.1.1.2 抛出异常,可以使用 throw 语句在代码块中的任何地方抛出异常。throw 语句的操作数可以是任意的表达式
- 13.1.1.3 捕获异常,catch 块跟在 try 块后面,用于捕获异常。您可以指定想要捕捉的异常类型,这是由 catch 关键字后的括号内的异常声明决定的。
- 13.1.2 定义新异常
- 13.1.2.1 C++标准的异常,C++ 提供了一系列标准的异常,定义在 <exception> 中,我们可以在程序中使用这些标准的异常。
- 13.1.2.2 定义新的异常,可以通过继承和重载 exception 类来定义新的异常。
13.2 异常体系说明
- 13.2.1 异常体系详解
- 13.2.1.1 std::exception,该异常是所有标准 C++ 异常的父类。
- 13.2.1.2 std::bad_alloc,该异常可以通过 new 抛出。
- 13.2.1.3 std::bad_cast,该异常可以通过 dynamic_cast 抛出。
- 13.2.1.4 std::bad_typeid,该异常可以通过 typeid 抛出。
- 13.2.1.5 std::bad_exception,这在处理 C++ 程序中无法预期的异常时非常有用。
- 13.2.1.6 std::logic_error,理论上可以通过读取代码来检测到的异常。
- 13.2.1.7 std::runtime_error,理论上不可以通过读取代码来检测到的异常。
- 13.2.2 读取代码检测异常
- 13.2.3 不可通过读取代码检测异常
- 13.2.3.1 std::overflow_error,当发生数学上溢时,会抛出该异常。
- 13.2.3.2 std::range_error,当尝试存储超出范围的值时,会抛出该异常。
- 13.2.3.3 std::underflow_error,当发生数学下溢时,会抛出该异常。
13.3 异常捕获设计
- 13.3.1 异常捕获原理
14.第十四天:STL标准模板库
14.1 C++ 标准模板库
- 14.1.1 STL标准库
- 14.1.1.1 什么是STL,C++ 标准模板库(STL)是一套功能强大的 C++ 模板类和函数的集合,它提供了一系列通用的、可复用的算法和数据结构。
- 14.1.1.2 STL的好处,具有代码重用、可移植性、高效性、抽象性、安全性和丰富的功能等优点。
- 14.1.1.3 STL重要组件,STL包括容器(Containers)、算法(Algorithms)和迭代器(Iterators)多个主要组件。
14.2 STL 算法
- 14.2.1 非修改性算法
- 14.2.1.1 find:在容器中查找指定元素,它返回一个迭代器,指向第一个匹配的元素,如果没有找到匹配的元素,则返回容器的end()迭代器。
- 14.2.1.2 count:计算容器中指定元素的个数
- 14.2.1.3 min_element和max_element:找到容器中的最小和最大元素
- 14.2.1.4 all_of、any_of和none_of:检查容器中的元素是否满足特定条件
- 14.2.1.5 accumulate:计算容器中元素的累加和
- 14.2.1.6 equal:比较两个容器是否相等
- 14.2.1.7 find_if:在容器中查找满足特定条件的元素
- 14.2.2 修改性算法
- 14.2.2.1 sort:对容器进行排序
- 14.2.2.2 reverse:反转容器中的元素顺序
- 14.2.2.3 fill:将容器中的元素设置为指定的值
- 14.2.2.4 transform:对容器中的元素进行转换操作
- 14.2.2.5 remove和remove_if:从容器中删除指定元素或满足特定条件的元素
- 14.2.2.6 replace和replace_if:将容器中的元素替换为指定的值或满足特定条件的值
- 14.2.3 区间算法
- 14.2.3.1 copy:将一个容器的元素复制到另一个容器
- 14.2.3.2 merge:合并两个有序容器
- 14.2.3.3 unique:从容器中删除重复的元素
- 14.2.3.4 partition:根据特定条件将容器分成两个部分
- 14.2.3.5 sort和stable_sort:对容器中的一部分元素进行排序
14.3 STL 迭代器
14.4 STL 适配器
14.5 STL 函数对象
15.第十五天:高级教程
15.1 预处理器
- 15.1.1 预处理器
- 15.1.1.1 什么是预处理器,预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。
- 15.1.1.2 #define 预处理,#define是一个预处理指令,用于定义宏(Macro)。宏是一种在编译时进行文本替换的机制,可以用来定义常量、函数宏、条件编译等。
- 15.1.1.3 参数宏,可以使用 #define 来定义一个带有参数的宏
- 15.1.1.4 条件编译,有几个指令可以用来有选择地对部分程序源代码进行编译。这个过程被称为条件编译。
- 15.1.1.5 # 和 ## 运算符,# 字符串化的意思,出现在宏定义中的#是把跟在后面的参数转换成一个字符串。## 连接符号,把参数连在一起。
- 15.1.2 预定义宏
- 15.1.2.1 什么是预定义宏,有一些预定义的宏(Predefined Macros)可以在编译时使用,它们提供了关于编译环境和代码特性的信息。
- 15.1.2.2 __cplusplus 预定义宏,表示当前编译器对C++标准的支持级别。它的值是一个整数,表示C++标准的年份。
- 15.1.2.3 FILE__和__LINE,使用__FILE__和__LINE__获取当前源文件的文件名和行号
- 15.1.2.4 FUNCTION,使用__FUNCTION__获取当前函数的名称
- 15.1.2.5 DATE__和__TIME,使用__DATE__和__TIME__获取编译的日期和时间
15.2 信号处理
- 15.2.1 信号处理机制
- 15.2.1.1 什么是信号处理,信号处理(Signal Handling)是一种处理异步事件的机制。
- 15.2.1.2 信号处理案例,信号是由操作系统或其他进程发送给进程的消息,用于通知进程发生了某种事件,如中断、错误或其他特定条件。
- 15.2.1.3 signal() 函数,signal()函数用于设置信号处理函数,返回值是一个指向之前信号处理函数的指针。如果之前没有设置过信号处理函数,则返回SIG_DFL或SIG_IGN。
- 15.2.1.4 raise() 函数,该函数用于向当前进程发送信号。返回一个整数值,表示函数执行的结果。如果成功发送信号,则返回0;否则,返回非零值。