├── .gitignore ├── Chapter_01_基础语法 ├── 01_Hello_World.cpp ├── 02_Const_and_Pointer.cpp ├── 03_Pointer_and_Array.cpp ├── 04_Pointer_and_Function.cpp ├── 05_Hello_Struct.cpp ├── 06_struct_02.cpp ├── 07_struct_03.cpp ├── 08_struct_04_const.cpp ├── 09_struct_05_project.cpp └── 10_address_book_project.cpp ├── Chapter_02_面向对象编程 ├── 00_blank_templet.cpp ├── 01_内存四区_全局区.cpp ├── 02_内存四区_栈区.cpp ├── 03_内存四区_堆区.cpp ├── 04_new.cpp ├── 05_引用_01.cpp ├── 06_引用_02_做函数参数.cpp ├── 07_引用_03_做函数返回值.cpp ├── 08_引用_04.cpp ├── 09_引用_05_常量引用.cpp ├── 10_函数_01_默认参数.cpp ├── 11_函数_02_占位参数.cpp ├── 12_函数_03_函数重载.cpp ├── 13_类与对象_封装_01.cpp ├── 14_类与对象_封装_02.cpp ├── 15_类与对象_封装_03.cpp ├── 16_类与对象_对象特征_01.cpp ├── 17_类与对象_对象特征_02.cpp ├── 18_类与对象_对象特征_03.cpp ├── 19_类与对象_对象特征_04.cpp ├── 20_类与对象_对象特征_05.cpp ├── 21_类与对象_对象特征_06.cpp ├── 22_类与对象_对象特征_07.cpp ├── 23_类与对象_对象特征_08.cpp ├── 24_类与对象_对象特征_09.cpp ├── 25_类与对象_对象特征_10.cpp ├── 26_类与对象_对象特征_11.cpp ├── 27_类与对象_对象特征_12.cpp ├── 28_类与对象_友元_01.cpp ├── 29_类与对象_友元_02.cpp ├── 30_类与对象_友元_03.cpp ├── 31_类与对象_运算符重载_01.cpp ├── 32_类与对象_运算符重载_02.cpp ├── 33_类与对象_运算符重载_03.cpp ├── 34_类与对象_运算符重载_04.cpp ├── 35_类与对象_运算符重载_05.cpp ├── 36_类与对象_运算符重载_06.cpp ├── 37_类与对象_继承_01.cpp ├── 38_类与对象_继承_02.cpp ├── 39_类与对象_继承_03.cpp ├── 40_类与对象_继承_04.cpp ├── 41_类与对象_继承_05.cpp ├── 42_类与对象_继承_06.cpp ├── 43_类与对象_继承_07.cpp ├── 44_类与对象_多态_01.cpp ├── 45_类与对象_多态_02.cpp ├── 46_类与对象_多态_03.cpp ├── 47_类与对象_多态_04.cpp ├── 48_类与对象_多态_05.cpp ├── 49_类与对象_多态_06.cpp ├── 50_文件操作_文本文件_01.cpp ├── 51_文件对象_文本文件_02.cpp ├── 52_文件操作_二进制文件_01.cpp ├── 53_文件操作_二进制文件_02.cpp ├── 54_综合案例_职工管理系统 │ ├── boss.cpp │ ├── boss.h │ ├── empFile.txt │ ├── emplouee.cpp │ ├── employee.h │ ├── main.cpp │ ├── manager.cpp │ ├── manager.h │ ├── worker.h │ ├── workerManager.cpp │ └── workerManager.h ├── person.txt └── test.txt ├── Chapter_03_模板 ├── 00_blank_templet.cpp ├── 01_函数模板基本语法.cpp ├── 02_函数模板注意事项.cpp ├── 03_函数模板案例_数组排序.cpp ├── 04_普通函数与函数模板区别.cpp ├── 05_普通函数与函数模板的调用规则.cpp ├── 06_模板的局限性.cpp ├── 07_类模板基本语法.cpp ├── 08_类模板与函数模板区别.cpp ├── 09_类模板中成员函数创建时机.cpp ├── 10_类模板对象做函数参数.cpp ├── 11_类模板与继承.cpp ├── 12_类模板成员函数类外实现.cpp ├── 13_类模板的分文件编写 │ ├── 13_Person.cpp │ ├── 13_Person.h │ ├── 13_Person.hpp │ └── 13_类模板的分文件编写.cpp ├── 14_类模板与友元.cpp └── 15_类模板案例_自定义数组类 │ ├── MyArray.hpp │ └── main.cpp ├── Chapter_04_STL_容器 ├── 00_blank_templet.cpp ├── 01_STL基本概念.md ├── 02_vector存放内置数据类型.cpp ├── 03_vector存放自定义数据类型.cpp ├── 04_vector容器嵌套容器.cpp ├── 05_string_构造函数.cpp ├── 06_string_赋值操作.cpp ├── 07_string_字符串拼接.cpp ├── 08_string_查找与替换.cpp ├── 09_string_字符串比较.cpp ├── 10_string_字符存取.cpp ├── 11_string_字符串插入与删除.cpp ├── 12_string_子串获取.cpp ├── 13_vector_构造函数.cpp ├── 14_vector_赋值操作.cpp ├── 15_vector_容量与大小.cpp ├── 16_vector_插入与删除.cpp ├── 17_vector_数据存取.cpp ├── 18_vector_互换容器.cpp ├── 19_vector_预留空间.cpp ├── 20_deque_构造函数.cpp ├── 21_deque_赋值操作.cpp ├── 22_deque_大小操作.cpp ├── 23_deque_插入与删除.cpp ├── 24_deque_数据存取.cpp ├── 25_deque_排序.cpp ├── 26_案例_评委打分.cpp ├── 27_stack_基本概念与常用接口.cpp ├── 28_queue_基本概念与常用接口.cpp ├── 29_list_基本概念与构造函数.cpp ├── 30_list_赋值与交换.cpp ├── 31_list_大小操作.cpp ├── 32_list_插入与删除.cpp ├── 33_list_数据存取.cpp ├── 34_list_反转与排序.cpp ├── 35_list_排序案例.cpp ├── 36_set_multiset_基本概念_构造与赋值.cpp ├── 37_set_大小与交换.cpp ├── 38_set_插入与删除.cpp ├── 39_set_查找与统计.cpp ├── 40_set与multiset区别.cpp ├── 41_pair_对组创建.cpp ├── 42_set_内置类型指定规则排序.cpp ├── 43_set_自定义数据类型排序.cpp ├── 44_map_multimap_基本概念_构造与赋值.cpp ├── 45_map_大小与交换.cpp ├── 46_map_插入与删除.cpp ├── 47_map_查找与统计.cpp ├── 48_map_排序.cpp └── 49_案例_员工分组.cpp ├── Chapter_05_STL_函数对象 ├── 01_函数对象_基本使用.cpp ├── 02_谓词_一元谓词.cpp ├── 03_谓词_二元谓词.cpp ├── 04_内建函数对象_算数仿函数.cpp ├── 05_内建函数对象_关系仿函数.cpp └── 06_内建函数对象_逻辑仿函数.cpp ├── Chapter_06_STL_常用算法 ├── 01_遍历_for_each.cpp ├── 02_遍历_transform.cpp ├── 03_查找_find.cpp ├── 04_查找_find_if.cpp ├── 05_查找_adjacent_find.cpp ├── 06_查找_binary_search.cpp ├── 07_查找_count.cpp ├── 08_查找_count_if.cpp ├── 09_排序_sort.cpp ├── 10_排序_random_shuffle.cpp ├── 11_排序_merge.cpp ├── 12_排序_reverse.cpp ├── 13_拷贝与替换_copy.cpp ├── 14_拷贝与替换_replace.cpp ├── 15_拷贝与替换_replace_if.cpp ├── 16_拷贝与替换_swap.cpp ├── 17_算数生成_accmulate.cpp ├── 18_算数生成_fill.cpp ├── 19_集合_set_intersection.cpp ├── 20_集合_set_union.cpp ├── 21_集合_set_difference.cpp └── 22_案例_演讲比赛流程管理系统 │ ├── main.cpp │ ├── speaker.h │ ├── speech.csv │ ├── speechManager.cpp │ └── speechManager.h ├── Chapter_07_案例_机房预约系统 ├── computerRoom.h ├── globalFile.h ├── identity.h ├── main.cpp ├── manager.cpp ├── manager.h ├── orderFile.cpp ├── orderFile.h ├── records │ ├── admin.txt │ ├── computerRooms.txt │ ├── order.txt │ ├── students.txt │ └── teachers.txt ├── student.cpp ├── student.h ├── teacher.cpp └── teacher.h ├── Chapter_08_模板_进阶 ├── 01_typed.cpp ├── 02_untyped.cpp ├── 03_macro.cpp ├── 04_functmpl.cpp ├── 05_double_compile.cpp ├── 06_deduction.cpp ├── 07_overload.cpp ├── 08_clstmpl.cpp ├── 09_clstmpl.cpp ├── 10_static.cpp ├── 11_recursion.cpp ├── 12_special.cpp ├── 13_partial.cpp ├── 14_default.cpp ├── 15_valparam.cpp ├── 16_membervar.cpp ├── 17_memberfunc.cpp ├── 18_membertype.cpp ├── 19_tmplargs.cpp ├── 20_nested_dependency.cpp ├── 21_temperror.cpp ├── 22_this.cpp ├── 23_init.cpp └── 24_virtual.cpp ├── Chapter_09_实现链表容器 └── list.cpp ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # VS Code 35 | *.vscode/ -------------------------------------------------------------------------------- /Chapter_01_基础语法/01_Hello_World.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define name "muzing" 5 | 6 | int add(int num1, int num2) 7 | { 8 | int sum = num1 + num2; 9 | return sum; 10 | } 11 | 12 | int main() 13 | { 14 | 15 | // int arr[2][2] = {10, 20, 30, 40}; 16 | 17 | // for (int i = 0; i < 2; i++) 18 | // { 19 | // for (int j = 0; j < 2; j++) 20 | // cout << arr[i][j] << endl; 21 | // } 22 | 23 | // cout << arr << endl; 24 | 25 | // cout << add(2, 3) << endl; 26 | 27 | // int a = 10; 28 | // int *p = &a; 29 | 30 | // cout << &a << endl; 31 | // cout << p << endl; 32 | // cout << *p << endl; 33 | // cout << sizeof(p) << endl; 34 | 35 | // 空指针 36 | // int *p = NULL; 37 | // cout << p << endl; 38 | 39 | // 野指针 40 | int *p = (int *)0x1111; 41 | cout << *p << endl; // 运行时会报错 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chapter_01_基础语法/02_Const_and_Pointer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | // const 修饰指针 7 | 8 | // 1. const 修饰指针 —— 常量指针 9 | // 2. const 修饰常量 —— 指针常量 10 | // 3. const 既修饰指针,又修饰常量 11 | 12 | int a = 10; 13 | int b = 10; 14 | 15 | // 常量指针 16 | // 指针的指向可以修改,但指针指向的值不能修改 17 | // const int *p = &a; 18 | 19 | //*p = 20; // 会报错 20 | // p = &b; // 可以改指向 21 | 22 | // 指针常量 23 | // 指针指向不能改,指针指向的值可以修改 24 | 25 | int *const p = &a; 26 | // *p = 20; // 可以改 27 | // p = &b; // 不能改指向 28 | 29 | // const int *const p = &a; 30 | // *p = 20; // 不可改 31 | // p = &b; // 不能改指向 32 | 33 | return 0; 34 | } -------------------------------------------------------------------------------- /Chapter_01_基础语法/03_Pointer_and_Array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | //利用指针访问数组中的元素 7 | int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 8 | 9 | int *p = arr; //arr 即为数组首地址 10 | // cout << *p << endl; 11 | // p++; //让指针向后偏移 12 | // cout << *p << endl; 13 | 14 | for (int i = 0; i < 10; i++) 15 | { 16 | cout << *p << endl; 17 | p++; 18 | } 19 | return 0; 20 | } -------------------------------------------------------------------------------- /Chapter_01_基础语法/04_Pointer_and_Function.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 实现两个数字进行交换 5 | 6 | void swap01(int a, int b) 7 | { 8 | int temp = a; 9 | a = b; 10 | b = temp; 11 | cout << "swap01 a = " << a << endl; //交换了(形参) 12 | cout << "swap01 b = " << b << endl; 13 | } 14 | 15 | void swap02(int *p1, int *p2) 16 | { 17 | int temp = *p1; 18 | *p1 = *p2; 19 | *p2 = temp; 20 | } 21 | 22 | void bubbleSort(int *arr, int len) 23 | { 24 | for (int i = 0; i < len - 1; i++) 25 | { 26 | for (int j = 0; j < len - i - 1; j++) 27 | { 28 | if (arr[j] > arr[j + 1]) 29 | { 30 | int temp = arr[j]; 31 | arr[j] = arr[j + 1]; 32 | arr[j + 1] = temp; 33 | } 34 | } 35 | } 36 | } 37 | 38 | int main() 39 | { 40 | // 指针与函数 41 | 42 | int a = 10; 43 | int b = 20; 44 | 45 | //1、值传递 46 | swap01(a, b); 47 | // cout << "a = " << a << endl; //其实并没有交换(实参) 48 | // cout << "b = " << b << endl; 49 | 50 | // 2、地址传递 51 | // 如果是地址传递,可以修饰实参 52 | swap02(&a, &b); 53 | cout << "a = " << a << endl; 54 | cout << "b = " << b << endl; 55 | 56 | //案例:封装一个函数,利用冒泡排序,实现对整型数组的升序排列 57 | 58 | int arr[10] = {4, 3, 6, 9, 1, 2, 10, 8, 7, 5}; 59 | int len = sizeof(arr) / sizeof(arr[0]); //数组长度 60 | bubbleSort(arr, len); 61 | cout << arr[0] << endl; 62 | 63 | return 0; 64 | } -------------------------------------------------------------------------------- /Chapter_01_基础语法/05_Hello_Struct.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 结构体属于用户自定义的数据类型,允许用户存储不同的数据类型 5 | 6 | // 1、创建语法: struct 类型名称 {成员列表}; 7 | // 2、通过学生类型创建具体学生 8 | 9 | struct Student 10 | { 11 | //成员列表 12 | string name; 13 | int age; 14 | int score; 15 | } s3; //顺便创建结构体变量,不建议用 16 | 17 | int main() 18 | { 19 | // 2.1 struct Student s1 20 | // struct Student s1; 21 | // struct 关键字可以省略 22 | Student s1; 23 | // 给 s1 赋值,通过.访问结构体变量中的属性 24 | s1.name = "muzing"; 25 | s1.age = 21; 26 | s1.score = 61; 27 | 28 | cout << s1.name << endl; 29 | 30 | // 2.2 struct Student s2 = {...} 创建时赋值 31 | struct Student s2 = {"张三", 19, 80}; 32 | cout << s2.age << endl; 33 | 34 | // 2.3 在定义结构体时顺便创建结构体变量 35 | s3.name = "李四"; 36 | cout << s3.name << endl; 37 | 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Chapter_01_基础语法/06_struct_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct student 5 | { 6 | string name; 7 | int age; 8 | int score; 9 | }; 10 | 11 | int main() 12 | { 13 | // 结构体数组 14 | // 作用:将自定义的结构体放入到数组中方便维护 15 | // 语法: struct 结构体名 数组名[元素个数] = { {}, {}, ... {}} 16 | 17 | struct student stuArr[3] = 18 | { 19 | {"张三", 18, 60}, 20 | {"李四", 19, 90}, 21 | {"王五", 19, 61}}; 22 | 23 | stuArr[2].name = "赵六"; 24 | 25 | for (int i = 0; i < 3; i++) 26 | { 27 | 28 | cout << stuArr[i].name << endl; 29 | cout << stuArr[i].age << endl; 30 | cout << stuArr[i].score << endl; 31 | } 32 | 33 | // 结构体指针 34 | // 作用:通过指针访问结构体中的成员 35 | // 可以利用操作符 -> 通过结构体指针访问结构体属性 36 | 37 | struct student stu = {"muzing", 18, 100}; 38 | // 通过指针指向结构体变量 39 | struct student *p = &stu; 40 | // 通过指针访问结构体变量中的数据 41 | cout << p->name << endl; 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /Chapter_01_基础语法/07_struct_03.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 结构体嵌套结构体 5 | struct student 6 | { 7 | string name; 8 | int age; 9 | int score; 10 | }; 11 | 12 | struct teacher 13 | { 14 | int id; 15 | string name; 16 | struct student stu; // 子结构体,学生 17 | }; 18 | 19 | // 结构体做函数参数 20 | 21 | // 值传递 22 | void printStudent1(student stu) 23 | { 24 | stu.age = 21; 25 | cout << "printStudent1" << stu.name << stu.age << stu.score << endl; 26 | } 27 | 28 | // 地址传递 29 | void printStudent2(struct student *p) 30 | { 31 | p->age = 25; 32 | cout << "printStudent1" << p->name << endl; 33 | } 34 | 35 | int main() 36 | { 37 | // 结构体嵌套 38 | teacher t; 39 | t.id = 10086; 40 | t.name = "老王"; 41 | t.stu.name = "张三"; 42 | t.stu.age = 20; 43 | t.stu.score = 60; 44 | 45 | // cout << t.name << endl; 46 | // cout << t.stu.name << endl; 47 | 48 | // 结构体做函数参数 49 | struct student s; 50 | s.name = "李四"; 51 | s.age = 20; 52 | s.score = 70; 53 | 54 | printStudent1(s); 55 | cout << s.age << endl; // 仍为20,修改形参不影响实参 56 | 57 | printStudent2(&s); 58 | cout << s.age << endl; // 已改为25 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /Chapter_01_基础语法/08_struct_04_const.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 用const来防止误操作 5 | 6 | struct student 7 | { 8 | string name; 9 | int age; 10 | int score; 11 | }; 12 | 13 | // 将函数中的形参改为指针,可减小内存开销(不会复制一份整个结构体) 14 | void printStudent(const student *stu) // 加const防止函数体中的误操作 15 | { 16 | //stu->age = 100; // 操作失败,因为加了const修饰 17 | cout << stu->name << stu->age << stu->score << endl; 18 | } 19 | 20 | int main() 21 | { 22 | student stu = {"张三", 18, 100}; 23 | printStudent(&stu); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /Chapter_01_基础语法/09_struct_05_project.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 结构体案例 5 | 6 | // 1.设计英雄结构体 7 | 8 | struct Hero 9 | { 10 | string name; 11 | int age; 12 | string sex; 13 | }; 14 | 15 | // 冒泡排序,实现年龄升序排列 16 | void bubbleSort(struct Hero heroArray[], int len) 17 | { 18 | for (int i = 0; i < len - 1; i++) 19 | { 20 | for (int j = 0; j < len - 1 - i; j++) 21 | { 22 | if (heroArray[j].age > heroArray[j + 1].age) 23 | { 24 | struct Hero temp = heroArray[j]; 25 | heroArray[j] = heroArray[j + 1]; 26 | heroArray[j + 1] = temp; 27 | } 28 | } 29 | } 30 | } 31 | 32 | // 打印排序后数组中的信息 33 | void printHero(struct Hero heroArray[], int len) 34 | { 35 | for (int i = 0; i < len; i++) 36 | { 37 | cout << "姓名:" << heroArray[i].name << "年龄:" << heroArray[i].age << "性别:" << heroArray[i].sex << endl; 38 | } 39 | } 40 | 41 | int main() 42 | { 43 | // 2.创建数组存放5名英雄 44 | struct Hero heroArray[5] = 45 | { 46 | {"刘备", 23, "男"}, 47 | {"关羽", 22, "男"}, 48 | {"张飞", 20, "男"}, 49 | {"赵云", 21, "男"}, 50 | {"貂蝉", 19, "女"}}; 51 | 52 | int len = sizeof(heroArray) / sizeof(heroArray[0]); 53 | 54 | // 3.对数组进行排序,按年龄进行升序排序 55 | bubbleSort(heroArray, len); 56 | 57 | // 4.将排序后结果打印输出 58 | printHero(heroArray, len); 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/00_blank_templet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | 7 | return 0; 8 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/01_内存四区_全局区.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 程序的内存模型 - 内存四区 5 | 6 | // 全局变量 7 | int g_a = 10; 8 | int g_b = 10; 9 | 10 | const int c_g_a = 10; 11 | const int c_g_b = 10; 12 | 13 | int main() 14 | { 15 | // 全局区:全局变量、静态变量、常量 16 | 17 | // 创建普通局部变量 18 | int a = 10; 19 | int b = 10; 20 | 21 | cout << "局部变量a的地址 " << &a << endl; 22 | cout << "局部变量b的地址 " << &a << endl; 23 | 24 | // 全局变量 25 | cout << "全局变量g_a的地址 " << &g_a << endl; 26 | cout << "全局变量g_b的地址 " << &g_b << endl; 27 | 28 | // 静态变量 29 | static int s_a = 10; 30 | static int s_b = 10; 31 | cout << "静态变量s_a的地址 " << &s_a << endl; 32 | cout << "静态变量s_b的地址 " << &s_b << endl; 33 | 34 | // 常量(字符串常量、const修饰的变量) 35 | // 字符串常量 36 | cout << "字符串常量的地址 " << &"Hello World!" << endl; 37 | // const修饰的变量(修饰全局变量、局部变量) 38 | cout << "全局常量c_g_a的地址 " << &c_g_a << endl; 39 | cout << "全局常量c_g_b的地址 " << &c_g_b << endl; 40 | const int c_l_a = 10; 41 | const int c_l_b = 10; 42 | cout << "局部常量c_l_a的地址 " << &c_l_a << endl; 43 | cout << "局部常量c_l_b的地址 " << &c_l_b << endl; 44 | 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/02_内存四区_栈区.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 栈区数据注意事项 —— 不要返回局部变量的地址 5 | // 栈区的数据由编译器管理开辟和释放 6 | 7 | int *func() // 形参数据也会放在栈区 8 | { 9 | int a = 10; // 局部变量,存放在栈区,栈区的数据在函数执行完后自动释放 10 | return &a; // 编译失败 11 | } 12 | 13 | int main() 14 | { 15 | int *p = func(); 16 | cout << *p << endl; 17 | cout << *p << endl; 18 | return 0; 19 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/03_内存四区_堆区.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 在堆区开辟数据 5 | 6 | int *func() 7 | { 8 | // 利用new关键字 可以将数据开辟到堆区 9 | int *a = new int(10); // 用指针存储new返回的内存地址 10 | // 指针本质上也是局部变量,放在栈上 指针保存的数据放在堆区 11 | return a; 12 | } 13 | 14 | int main() 15 | { 16 | int *p = func(); 17 | cout << *p << endl; 18 | cout << *p << endl; 19 | return 0; 20 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/04_new.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // new的基本语法 5 | 6 | int *func() 7 | { 8 | // 在堆区创建整形数据 9 | // new返回的是该数据类型的指针 10 | int *p = new int(10); 11 | return p; 12 | } 13 | 14 | // 在堆区开辟数组 15 | 16 | void test02() 17 | { 18 | // 在堆区创建长度为10的整形数据的数组 19 | int *arr = new int[10]; // 此处的10代表数组中有10个元素 20 | for (int i = 0; i < 10; i++) 21 | { 22 | arr[i] = i; // 为元素赋值 23 | } 24 | for (int i = 0; i < 10; i++) 25 | { 26 | cout << arr[i] << endl; 27 | } 28 | delete[] arr; // 释放数组时需要加[] 29 | } 30 | 31 | int main() 32 | { 33 | int *p = func(); 34 | cout << *p << endl; 35 | // 堆区的数据由程序员开辟,程序员释放 36 | delete p; // 释放 37 | cout << *p << endl; // 会报错(读写权限冲突异常)或读出其他数(乱码) 38 | 39 | test02(); 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/05_引用_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | // 引用基本语法 7 | // 数据类型 &别名 = 原名 8 | 9 | int a = 10; 10 | // 创建引用 11 | int &b = a; 12 | 13 | // 引用必须初始化 14 | // int &c; //错误,未初始化 15 | 16 | cout << "a = " << a << endl; 17 | cout << "b = " << b << endl; 18 | 19 | b = 20; 20 | 21 | cout << "a = " << a << endl; 22 | cout << "b = " << b << endl; 23 | 24 | // 引用在初始化后,不可以更改 25 | int d = 100; 26 | b = d; // 这行代码为赋值,而不能将b改为d的引用 27 | 28 | cout << a << endl; 29 | 30 | return 0; 31 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/06_引用_02_做函数参数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 值传递 5 | void mySwap01(int a, int b) 6 | { 7 | int temp = a; 8 | a = b; 9 | b = temp; 10 | } 11 | 12 | // 地址传递 13 | void mySwap02(int *a, int *b) 14 | { 15 | int temp = *a; 16 | *a = *b; 17 | *b = temp; 18 | } 19 | 20 | // 引用传递 21 | void mySwap03(int &a, int &b) 22 | { 23 | int temp = a; 24 | a = b; 25 | b = temp; 26 | } 27 | 28 | int main() 29 | { 30 | // 作用:函数传参时,可以利用引用的技术让形参修饰实参 31 | // 优点:可以简化指针修改实参 32 | 33 | int a = 10; 34 | int b = 20; 35 | 36 | // mySwap01(a, b); // 值传递,形参不会修饰实参 37 | // mySwap02(&a, &b); 38 | mySwap03(a, b); // 引用传递,形参会修饰实参 39 | 40 | cout << "a = " << a << endl; 41 | cout << "b = " << b << endl; 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/07_引用_03_做函数返回值.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 返回局部变量引用 5 | // int &test01() 6 | // { 7 | // int a = 10; // 局部变量 存放在内存四区中的栈区 8 | // return a; 9 | // } 10 | 11 | // 返回静态变量引用 12 | int &test02() 13 | { 14 | static int a = 20; 15 | return a; 16 | } 17 | 18 | int main() 19 | { 20 | // 引用可以作为函数返回值 21 | // 注意:不要返回局部变量引用 22 | // 用法:函数调用作为左值 23 | 24 | // int &ref = test01(); // 编译时会报错 25 | int &ref = test02(); // 编译时会报错 26 | 27 | cout << "ref = " << ref << endl; 28 | 29 | test02() = 1000; // 相当于 a = 1000; 30 | 31 | // 如果函数的返回值是引用,则该函数调用可以作为左值 32 | 33 | cout << "ref = " << ref << endl; 34 | 35 | return 0; 36 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/08_引用_04.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 引用的本质:指针常量 5 | 6 | void func(int &ref) 7 | { 8 | ref = 100; // ref是引用,转换为 *ref = 100 9 | } 10 | 11 | int main() 12 | { 13 | int a = 10; 14 | 15 | // 自动转换为 int * const ref = &a; 16 | // 指针常量为指针指向不可更改,也说明为什么引用不可更改 17 | int &ref = a; 18 | ref = 20; //内部发现ref是引用,自动帮我们转换为 *ref = 20; 19 | 20 | cout << "a:" << a << endl; 21 | cout << "ref:" << ref << endl; 22 | 23 | func(a); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/09_引用_05_常量引用.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 引用使用的场景:通常用来修饰形参 5 | void showValue(const int &v) 6 | { 7 | // v += 10; // 不能修改 8 | cout << v << endl; 9 | } 10 | 11 | int main() 12 | { 13 | int a = 10; 14 | // int &ref = 10; // 引用必须引一块合法的内存空间,本行为错误 15 | const int &ref = 10; //合法,编译器会将代码修改为 int temp = 10; const int & ref = temp; 16 | // ref = 20; // 加入const后为只读,不可修改 17 | 18 | showValue(a); 19 | return 0; 20 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/10_函数_01_默认参数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 函数默认参数 5 | 6 | int func(int a, int b = 10, int c = 10) 7 | { 8 | return a + b + c; 9 | } 10 | 11 | // 注意:如果某个位置参数有默认值,那么从这个位置往后都必须有默认值 12 | // 语法: 返回值类型 函数名 (形参 = 默认值) {函数体} 13 | 14 | // 如果函数声明有默认值,函数实现时就不能有默认参数 15 | int func2(int a = 10, int b = 10); 16 | 17 | int func2(int a, int b) 18 | { 19 | return a + b; 20 | } 21 | 22 | int main() 23 | { 24 | cout << func(10, 20, 30) << endl; 25 | cout << func(10) << endl; 26 | return 0; 27 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/11_函数_02_占位参数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 函数占位参数,占位参数也可以有默认参数 5 | // 语法: 返回值类型 函数名 (数据类型) {函数体} 6 | 7 | void func(int a, int = 10) 8 | { 9 | cout << "This is func" << endl; 10 | } 11 | 12 | int main() 13 | { 14 | 15 | func(10, 10); // 占位参数必须填补 16 | func(10); // 占位参数可以有默认值 17 | 18 | return 0; 19 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/12_函数_03_函数重载.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 函数重载 5 | /* 6 | 作用:函数名可以相同,提高复用性 7 | 8 | 条件: 9 | - 同一个作用域下 10 | - 函数名称相同 11 | - 函数参数类型不同或个数不同或顺序不同 12 | 13 | 注意:函数的返回值不可以作为函数重载的条件 14 | 15 | */ 16 | 17 | void func() 18 | { 19 | cout << "调用了func" << endl; 20 | } 21 | 22 | void func(int a) 23 | { 24 | cout << "调用了func(int a)" << endl; 25 | } 26 | 27 | void func(double a) 28 | { 29 | cout << "调用了func(double a)" << endl; 30 | } 31 | 32 | // 函数重载遇到引用 33 | // 有无 const 可以作为重载条件 34 | 35 | void func2(int &a) //func2(10) 等效于 int &a = 10; 不合法,故不使用本实现 36 | { 37 | cout << "调用了func2(int &a)" << endl; 38 | } 39 | 40 | void func2(const int &a) //func2(10) 等效于 const int &a = 10; 合法,使用本实现 41 | { 42 | cout << "调用了func2(const int &a)" << endl; 43 | } 44 | 45 | // 函数重载遇到默认参数 46 | 47 | void func3(int a) 48 | { 49 | cout << "调用了func3(int a)" << endl; 50 | } 51 | 52 | void func3(int a, int b = 10) 53 | { 54 | cout << "调用了func3(int a, int b = 10)" << endl; 55 | } 56 | 57 | int main() 58 | { 59 | func(); 60 | func(10); 61 | func(3.14); 62 | 63 | int a = 10; 64 | func2(a); // 对应 int &a 65 | func2(10); // 对应 const int &a 66 | 67 | // func3(10); // 出错,同时满足两种实现的参数情况,出现二义性,需要避免 68 | func3(10, 20); // 可以执行 69 | 70 | return 0; 71 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/13_类与对象_封装_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 设计一个圆类,求圆的周长 5 | 6 | // 圆周率 7 | const double Pi = 3.14; 8 | 9 | class Circle 10 | { 11 | // 访问权限:公共权限 12 | public: 13 | // 属性 14 | int m_r; // 半径 15 | 16 | // 行为 17 | // 获取圆的周长 18 | double calculate() 19 | { 20 | return 2 * Pi * m_r; 21 | } 22 | }; 23 | 24 | int main() 25 | { 26 | // 通过圆类 创建具体的圆(对象) 27 | // 实例化 28 | Circle c1; 29 | // 为圆对象的属性进行赋值 30 | c1.m_r = 10; 31 | 32 | cout << "圆的周长为 " << c1.calculate() << endl; 33 | return 0; 34 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/14_类与对象_封装_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 封装 —— 访问权限 5 | // 公共权限 public 成员 类内可以访问 类外可以访问 6 | // 保护权限 protected 成员 类内可以访问 类外不可以访问 子类可访问 7 | // 私有权限 private 成员 类内可以访问 类外不可以访问 子类不可访问 8 | 9 | class Person 10 | { 11 | public: 12 | string m_Name; 13 | 14 | protected: 15 | string m_Car; 16 | 17 | private: 18 | int m_Password; 19 | 20 | public: 21 | void func() 22 | { 23 | m_Name = "张三"; 24 | m_Car = "Nissan"; 25 | m_Password = 123456; 26 | } 27 | }; 28 | 29 | // class 与 struct 区别:默认访问权限不同,struct默认公共,class默认私有 30 | 31 | int main() 32 | { 33 | // 实例化 34 | Person p1; 35 | p1.m_Name = "李四"; 36 | // p1.m_Car = "Ford"; // 保护权限,类外不能访问,无法修改 37 | // p1.m_Password = 123; // 私有权限,类外不能访问,无法修改 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/15_类与对象_封装_03.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 成员属性设置为私有 5 | // 1、可以自己控制读写权限 6 | // 2、对于写可以检测数据的有消息 7 | 8 | class Person 9 | { 10 | public: 11 | // 设置姓名 12 | void setName(string name) 13 | { 14 | m_Name = name; 15 | } 16 | // 获取姓名 17 | string getName() 18 | { 19 | return m_Name; 20 | } 21 | // 获取年龄 22 | int getAge() 23 | { 24 | m_Age = 0; 25 | return m_Age; 26 | } 27 | // 设置年龄 28 | void setAge(int age) 29 | { 30 | if (age < 0 || age > 150) // 限制年龄范围 31 | { 32 | m_Age = 0; 33 | return; 34 | } 35 | m_Age = age; 36 | } 37 | 38 | void setLover(string lover) 39 | { 40 | m_Lover = lover; 41 | } 42 | 43 | private: 44 | string m_Name; // 姓名 可读可写 45 | int m_Age; // 年龄 可读,写有限制 46 | string m_Lover; //情人 只写 47 | }; 48 | 49 | int main() 50 | { 51 | Person p; 52 | p.setName("张三"); 53 | cout << p.getName() << endl; 54 | cout << p.getAge() << endl; 55 | return 0; 56 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/16_类与对象_对象特征_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 对象的初始化与清理 5 | // 1、构造函数 进行初始化操作 6 | // 2、析构函数 进行清理操作 7 | 8 | class Person 9 | { 10 | public: 11 | // 构造函数 12 | // 没有返回值 不用写 void 13 | // 函数名与类名相同 14 | // 构造函数可以有参数,可以发生重载 15 | // 创建对象时,构造函数会自动调用,且只调用一次 16 | Person() 17 | { 18 | cout << "Person 构造函数的调用" << endl; 19 | } 20 | // 析构函数 进行清理的操作 21 | // 没有返回值 不写 void 22 | // 函数名和类名相同 在名称前加 ~ 23 | // 析构函数无参数,因此不可以重载 24 | // 对象在销毁前会自动调用析构函数,且只调用一次 25 | ~Person() 26 | { 27 | cout << "Person 析构函数的调用" << endl; 28 | } 29 | }; 30 | 31 | void test01() 32 | { 33 | Person p; // 栈上的数据,test01执行完后会被释放 34 | } 35 | 36 | int main() 37 | { 38 | test01(); 39 | return 0; 40 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/17_类与对象_对象特征_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 构造函数的分类及调用 5 | 6 | // 分类: 7 | // 按照参数分类: 无参构造 与 有参构造 8 | // 按照类型分类: 普通构造 与 拷贝构造 9 | 10 | class Person 11 | { 12 | public: 13 | int age; 14 | 15 | // 无参构造(默认构造) 16 | Person() 17 | { 18 | cout << "Person的无参构造函数调用" << endl; 19 | } 20 | 21 | // 有参构造 22 | Person(int a) 23 | { 24 | age = a; 25 | cout << "Person的有参构造函数调用" << endl; 26 | } 27 | 28 | // 拷贝构造函数 29 | Person(const Person &p) 30 | { 31 | // 将传入的人身上的所有属性,拷贝过来 32 | age = p.age; 33 | cout << "Person的拷贝构造函数调用" << endl; 34 | } 35 | 36 | ~Person() 37 | { 38 | cout << "Person析构函数调用" << endl; 39 | } 40 | }; 41 | 42 | // 调用 43 | void test01() 44 | { 45 | // 1、括号法 46 | // Person p1; //默认构造函数调用 47 | // Person p2(10); // 有参构造函数 48 | // Person p3(p2); // 拷贝构造函数 49 | 50 | // 注意事项:调用默认构造函数时,不要加()(避免和函数声明语法冲突) 51 | // cout << p2.age << endl; 52 | // cout << p3.age << endl; 53 | 54 | // 2、显式法 55 | // Person p1; 56 | Person p2 = Person(10); // 调用有参构造 57 | Person p3 = Person(p2); // 拷贝构造 58 | 59 | // Person(10); // 匿名对象 特点:当前执行结束后,系统会立即回收掉匿名对象 60 | // 注意事项:不要利用拷贝构造函数来初始化匿名对象 61 | 62 | // 3、隐式转换法 63 | Person p4 = 10; // 相当于 Person p4 = Person(10); 64 | Person p5 = p4; // 拷贝构造 65 | } 66 | 67 | int main() 68 | { 69 | test01(); 70 | return 0; 71 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/18_类与对象_对象特征_03.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 拷贝构造函数调用时机 5 | // - 使用一个已经创建完毕的对象来初始化一个新对象 6 | // - 值传递的方式给函数参数传值 7 | // - 以值方式返回局部对象 8 | 9 | class Person 10 | { 11 | public: 12 | int m_Age; 13 | Person() 14 | { 15 | cout << "Person默认构造函数调用" << endl; 16 | } 17 | 18 | Person(int age) 19 | { 20 | m_Age = age; 21 | cout << "Person有参构造函数调用" << endl; 22 | } 23 | 24 | Person(const Person &p) 25 | { 26 | m_Age = p.m_Age; 27 | cout << "Person拷贝构造函数调用" << endl; 28 | } 29 | 30 | ~Person() 31 | { 32 | cout << "Person析构函数调用" << endl; 33 | } 34 | }; 35 | 36 | // 1、使用一个已经创建完毕的对象来初始化一个新对象 37 | void test01() 38 | { 39 | Person p1(20); 40 | Person p2(p1); 41 | cout << p2.m_Age << endl; 42 | } 43 | 44 | // 2、值传递的方式给函数参数传值 45 | void doWork(Person p) 46 | { 47 | } 48 | 49 | void test02() 50 | { 51 | Person p; 52 | doWork(p); 53 | } 54 | 55 | // 3、以值方式返回局部对象 56 | Person doWork2() 57 | { 58 | Person p1; 59 | cout << &p1 << endl; 60 | return p1; 61 | } 62 | 63 | void test03() 64 | { 65 | Person p = doWork2(); 66 | cout << &p << endl; 67 | } 68 | 69 | int main() 70 | { 71 | // test01(); 72 | test02(); 73 | // test03(); 74 | return 0; 75 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/19_类与对象_对象特征_04.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 构造函数调用规则 5 | 6 | /* 7 | 创建一个类,C++编译器会给每个类都添加至少3个函数 8 | 默认构造(空实现) 9 | 析构函数(空实现) 10 | 拷贝构造(值拷贝) 11 | */ 12 | 13 | // - 如果用户定义有参构造函数,C++不再提供默认无参构造,但会提供默认拷贝构造 14 | // - 如果用户定义拷贝构造函数,C++不会再提供其他构造函数 15 | 16 | class Person 17 | { 18 | public: 19 | Person() 20 | { 21 | cout << "Person的默认构造函数调用" << endl; 22 | } 23 | 24 | Person(int age) 25 | { 26 | cout << "Person的有参构造函数调用" << endl; 27 | m_Age = age; 28 | } 29 | 30 | Person(const Person &p) 31 | { 32 | m_Age = p.m_Age; 33 | cout << "Person的拷贝构造函数调用" << endl; 34 | } 35 | 36 | ~Person() 37 | { 38 | cout << "Person的析构函数调用" << endl; 39 | } 40 | int m_Age; 41 | }; 42 | 43 | // void test01() 44 | // { 45 | // Person p1; 46 | // p1.m_Age = 18; 47 | // Person p2(p1); 48 | // cout << p2.m_Age << endl; 49 | // } 50 | 51 | void test02() 52 | { 53 | // Person p; // 报错:无默认构造函数 54 | Person p1(20); 55 | Person p2(p1); 56 | cout << p2.m_Age << endl; 57 | } 58 | 59 | int main() 60 | { 61 | // test01(); 62 | test02(); 63 | return 0; 64 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/20_类与对象_对象特征_05.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 深拷贝与浅拷贝 5 | // 浅拷贝:简单的赋值拷贝操作 6 | // 深拷贝:在堆区重新申请空间,进行拷贝操作 7 | 8 | class Person 9 | { 10 | public: 11 | int m_Age; 12 | int *m_Height; 13 | 14 | Person() 15 | { 16 | cout << "Person的默认构造函数调用" << endl; 17 | } 18 | 19 | Person(int age, int height) 20 | { 21 | m_Age = age; 22 | m_Height = new int(height); 23 | cout << "Person的有参构造函数调用" << endl; 24 | } 25 | 26 | // 自己实现拷贝构造函数,解决浅拷贝带来的问题 27 | Person(const Person &p) 28 | { 29 | cout << "Person拷贝构造函数调用" << endl; 30 | m_Age = p.m_Age; 31 | // m_Height = p.m_Height; // 编译器默认实现 32 | // 深拷贝操作 33 | m_Height = new int(*p.m_Height); 34 | } 35 | 36 | ~Person() 37 | { 38 | // 析构代码,将堆区开辟数据释放操作 39 | if (m_Height != NULL) 40 | { 41 | delete m_Height; 42 | m_Height = NULL; 43 | } 44 | cout << "Person的析构函数调用" << endl; 45 | } 46 | }; 47 | 48 | void test01() 49 | { 50 | Person p1(18, 170); 51 | cout << "p1年龄为 " << p1.m_Age << " 身高为 " << *p1.m_Height << endl; 52 | Person p2(p1); 53 | cout << "p2年龄为 " << p2.m_Age << " 身高为 " << *p2.m_Height << endl; 54 | } 55 | 56 | int main() 57 | { 58 | test01(); 59 | return 0; 60 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/21_类与对象_对象特征_06.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 初始化列表 5 | // 语法: 构造函数():属性1(值1),属性2(值2) ... {函数体} 6 | 7 | class Person 8 | { 9 | public: 10 | int m_A; 11 | int m_B; 12 | int m_C; 13 | 14 | // 传统初始化操作 15 | // Person(int a, int b, int c) 16 | // { 17 | // m_A = a; 18 | // m_B = b; 19 | // m_C = c; 20 | // } 21 | 22 | // 初始化列表初始化属性 23 | Person(int a, int b, int c) : m_A(a), m_B(b), m_C(c) 24 | { 25 | } 26 | }; 27 | 28 | void test01() 29 | { 30 | Person p(10, 20, 30); 31 | cout << p.m_A << p.m_B << p.m_C << endl; 32 | } 33 | 34 | int main() 35 | { 36 | test01(); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/22_类与对象_对象特征_07.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 类对象作为类成员 5 | 6 | class Phone 7 | { 8 | public: 9 | Phone(string pName) 10 | { 11 | cout << "Phone的构造函数调用" << endl; 12 | m_PName = pName; 13 | } 14 | string m_PName; 15 | ~Phone() 16 | { 17 | cout << "Phone的析构函数调用" << endl; 18 | } 19 | }; 20 | 21 | class Person 22 | { 23 | public: 24 | string m_Name; 25 | Phone m_Phone; 26 | Person(string name, string pName) : m_Name(name), m_Phone(pName) 27 | { 28 | cout << "Person的构造函数调用" << endl; 29 | } 30 | ~Person() 31 | { 32 | cout << "Person的析构函数调用" << endl; 33 | } 34 | }; 35 | 36 | void test01() 37 | { 38 | Person p("张三", "HUAWEI"); 39 | cout << p.m_Name << "拿着" << p.m_Phone.m_PName << endl; 40 | } 41 | 42 | int main() 43 | { 44 | test01(); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/23_类与对象_对象特征_08.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 静态成员 5 | 6 | // 静态成员变量: 7 | // - 所有对象共享同一份数据 8 | // - 在编译阶段分配内存 9 | // - 类内声明,类外初始化 10 | 11 | // 静态成员函数 12 | // - 所有对象共享同一个函数 13 | // - 静态成员函数只能访问静态成员变量 14 | 15 | class Person 16 | { 17 | public: 18 | // 静态成员变量 19 | static int m_A; 20 | 21 | // 静态成员函数 22 | static void func() 23 | { 24 | m_A = 10; // 静态成员函数可以访问静态成员变量 25 | // m_C = 20; // 静态成员函数不可以访问非静态成员变量 26 | cout << "static void func调用" << endl; 27 | } 28 | 29 | int m_C; // 非静态成员变量 30 | 31 | private: 32 | //静态成员变量也是有访问权限的 33 | static int m_B; 34 | static void func2() 35 | { 36 | cout << "static void func2调用" << endl; 37 | } 38 | }; 39 | 40 | int Person::m_A = 100; 41 | int Person::m_B = 200; 42 | 43 | void test01() 44 | { 45 | Person p1; 46 | 47 | Person p2; 48 | p2.m_A = 200; 49 | cout << p1.m_A << endl; 50 | } 51 | 52 | void test02() 53 | { 54 | // 静态成员变量不属于某个对象上,所有对象都共享同一份数据 55 | // 因此静态成员变量有两种访问方式 56 | 57 | // 1、通过对象进行访问 58 | Person p; 59 | cout << p.m_A << endl; 60 | 61 | // 2、通过类名进行访问 62 | cout << Person::m_A << endl; 63 | // cout << Person::m_B << endl; // 类外访问不到私有静态成员变量 64 | } 65 | 66 | // 测试静态成员函数 67 | void test03() 68 | { 69 | // 1、通过对象访问 70 | Person p; 71 | p.func(); 72 | 73 | // 2、通过类名访问 74 | Person::func(); 75 | // Person::func2(); // 类外访问不到私有静态成员函数 76 | } 77 | 78 | int main() 79 | { 80 | // test01(); 81 | // test02(); 82 | test03(); 83 | return 0; 84 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/24_类与对象_对象特征_09.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // C++对象模型和this指针 5 | 6 | // 成员变量和成员函数分开存储 7 | 8 | class Person 9 | { 10 | int m_A; // 非静态成员变量,属于类的对象 11 | static int m_B; // 静态成员变量,不属于类的对象上 12 | void func() {} // 非静态成员函数,不属于类的对象上 13 | static void func2() {} // 静态成员函数,不属于类的对象上 14 | }; 15 | 16 | int Person::m_B = 10; 17 | 18 | void test01() 19 | { 20 | Person p; 21 | // 空对象占用内存空间为 1 22 | // C++ 编译器会给每个空对象也分配一个字节空间,以区分空对象占内存的位置 23 | // 每个空对象有一个独一无二的内存地址 24 | cout << "sizeof p = " << sizeof(p) << endl; 25 | } 26 | 27 | void test02() 28 | { 29 | Person p; 30 | cout << "sizeof p = " << sizeof(p) << endl; 31 | } 32 | 33 | int main() 34 | { 35 | // test01(); 36 | test02(); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/25_类与对象_对象特征_10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // this指针是隐含每一个非静态成员函数内的一种指针 5 | // this指针不需要定义,直接使用即可 6 | 7 | // this指针的用途 8 | 9 | // - 当形参和成员变量同名时,可用this指针来区分 10 | // - 在类的非静态成员函数中返回对象本身,可使用 return *this 11 | 12 | class Person 13 | { 14 | public: 15 | int age; 16 | Person(int age) 17 | { 18 | // this指针指向被调用的成员函数所属的对象 19 | this->age = age; 20 | } 21 | 22 | Person& PersonAddAge(Person &p) 23 | { 24 | this->age += p.age; 25 | return *this; 26 | } 27 | }; 28 | 29 | // 1、解决名称冲突 30 | void test01() 31 | { 32 | Person p1(18); 33 | cout << p1.age << endl; 34 | } 35 | 36 | // 2、返回对象本身用*this 37 | void test02() 38 | { 39 | Person p1(10); 40 | Person p2(10); 41 | 42 | // 链式编程思想 43 | p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1); 44 | 45 | cout << p2.age << endl; 46 | } 47 | 48 | int main() 49 | { 50 | // test01(); 51 | test02(); 52 | return 0; 53 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/26_类与对象_对象特征_11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 空指针访问成员函数 5 | 6 | class Person 7 | { 8 | public: 9 | void showClassName() 10 | { 11 | cout << "This is Person class." << endl; 12 | } 13 | 14 | int m_Age; 15 | void showPersonAge() 16 | { 17 | // 报错原因是因为传入的指针是NULL 18 | if (this == NULL) 19 | { 20 | return; 21 | } 22 | cout << "age = " << m_Age << endl; 23 | } 24 | }; 25 | 26 | void test01() 27 | { 28 | Person *p = NULL; 29 | p->showClassName(); 30 | p->showPersonAge(); 31 | } 32 | 33 | int main() 34 | { 35 | test01(); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/27_类与对象_对象特征_12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // const修饰成员函数 5 | 6 | // 常函数 7 | // - 成员函数后加const后我们称其为常函数 8 | // - 常函数内不可以修改成员属性 9 | // - 成员属性声明时加关键字mutable后,在常函数中依然可以修改 10 | 11 | class Person 12 | { 13 | public: 14 | Person() 15 | { 16 | } 17 | 18 | // this指针的本质是指针常量,指针的指向是不可以修改的 19 | // Person * const this; // this 指针相当于本行 20 | // const Person * const this; // 在成员函数后面加const,修饰的是this指针,让指针指向的值也不可以修改 21 | void showPerson() const 22 | { 23 | // this->m_A = 100; 24 | this->m_B = 100; 25 | // this = NULL; // this指针不可以修改指针的指向 26 | } 27 | int m_A; 28 | mutable int m_B; // 特殊变量,即使在常函数中也可以修改这个值,加关键字 mutable 29 | 30 | void func() 31 | { 32 | } 33 | }; 34 | 35 | void test01() 36 | { 37 | Person p; 38 | p.showPerson(); 39 | } 40 | 41 | // 常对象 42 | // - 声明对象前加const称该对象为常对象 43 | // - 常对象只能调用常函数 44 | 45 | void test02() 46 | { 47 | const Person p; // 在对象前加const,变为常对象 48 | // p.m_A = 100; // 报错,不允许修改 49 | p.m_B = 100; // m_B 特殊,在常对象下也可以修改 50 | 51 | // 常对象只能调用常函数 52 | p.showPerson(); 53 | // p.func(); // 不能调用普通成员函数,以防普通成员函数修改属性 54 | } 55 | 56 | int main() 57 | { 58 | // test01(); 59 | test02(); 60 | return 0; 61 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/28_类与对象_友元_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 友元:让一个函数或类访问另一个类中的私有成员 5 | 6 | // 全局函数做友元 7 | 8 | class Building 9 | { 10 | // goodFriend全局函数是Building的friend,可以访问Building中的私有成员 11 | friend void goodFriend(Building *building); 12 | 13 | public: 14 | Building() 15 | { 16 | m_SittingRoom = "客厅"; 17 | m_BedRoom = "卧室"; 18 | } 19 | 20 | string m_SittingRoom; 21 | 22 | private: 23 | string m_BedRoom; 24 | }; 25 | 26 | // 全局函数 27 | void goodFriend(Building *building) 28 | { 29 | cout << building->m_SittingRoom << endl; 30 | cout << building->m_BedRoom << endl; 31 | } 32 | 33 | void test01() 34 | { 35 | Building building; 36 | goodFriend(&building); 37 | } 38 | 39 | int main() 40 | { 41 | test01(); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/29_类与对象_友元_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 类做友元 5 | 6 | class Building; 7 | class goodFriend 8 | { 9 | public: 10 | goodFriend(); 11 | void visit(); //参观函数访问Building中的属性 12 | 13 | Building *building; 14 | }; 15 | 16 | class Building 17 | { 18 | // goodFriend类是Building类的friend,可以访问到私有内容 19 | friend class goodFriend; 20 | 21 | public: 22 | Building(); 23 | string m_SittingRoom; 24 | 25 | private: 26 | string m_BedRoom; 27 | }; 28 | 29 | // 类外写成员函数 30 | Building::Building() 31 | { 32 | m_SittingRoom = "客厅"; 33 | m_BedRoom = "卧室"; 34 | } 35 | 36 | goodFriend::goodFriend() 37 | { 38 | // 创建建筑物对象 39 | building = new Building; 40 | } 41 | 42 | void goodFriend::visit() 43 | { 44 | cout << building->m_SittingRoom << endl; 45 | cout << building->m_BedRoom << endl; 46 | } 47 | 48 | void test01() 49 | { 50 | goodFriend gf; 51 | gf.visit(); 52 | } 53 | 54 | int main() 55 | { 56 | test01(); 57 | return 0; 58 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/30_类与对象_友元_03.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 成员函数做友元 5 | 6 | class Building; 7 | class GoodFriend 8 | { 9 | public: 10 | GoodFriend(); 11 | 12 | void visit(); // 让visit函数可以访问Building中私有成员 13 | void visit2(); // 让visit2函数不可以访问Building中私有成员 14 | 15 | Building *building; 16 | }; 17 | 18 | class Building 19 | { 20 | // GoodFriend类下的visit成员函数为本类的friend,可以访问私有成员 21 | friend void GoodFriend::visit(); 22 | 23 | public: 24 | Building(); 25 | string m_SittingRoom; 26 | 27 | private: 28 | string m_BedRoom; 29 | }; 30 | 31 | // 类外实现成员函数 32 | 33 | Building::Building() 34 | { 35 | m_SittingRoom = "客厅"; 36 | m_BedRoom = "卧室"; 37 | } 38 | 39 | GoodFriend::GoodFriend() 40 | { 41 | building = new Building; 42 | } 43 | 44 | void GoodFriend::visit() 45 | { 46 | cout << "visit函数正在访问" << building->m_SittingRoom << endl; 47 | cout << "visit函数正在访问" << building->m_BedRoom << endl; 48 | } 49 | 50 | void GoodFriend::visit2() 51 | { 52 | cout << "visit2函数正在访问" << building->m_SittingRoom << endl; 53 | // cout << "visit2函数正在访问" << building->m_BedRoom << endl; 54 | } 55 | 56 | void test01() 57 | { 58 | GoodFriend gf; 59 | gf.visit(); 60 | gf.visit2(); 61 | } 62 | 63 | int main() 64 | { 65 | test01(); 66 | return 0; 67 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/31_类与对象_运算符重载_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 运算符重载: 5 | // 对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 6 | 7 | // 加号运算符重载 8 | 9 | class Person 10 | { 11 | public: 12 | int m_A; 13 | int m_B; 14 | 15 | // 1、成员函数重载 + 16 | // Person operator+(Person &p) 17 | // { 18 | // Person temp; 19 | // temp.m_A = this->m_A + p.m_A; 20 | // temp.m_B = this->m_B + p.m_B; 21 | // return temp; 22 | // } 23 | }; 24 | 25 | // 2、全局函数重载 + 26 | Person operator+(Person &p1, Person &p2) 27 | { 28 | Person temp; 29 | temp.m_A = p1.m_A + p2.m_A; 30 | temp.m_B = p1.m_B + p2.m_B; 31 | return temp; 32 | } 33 | 34 | // 函数重载版本 35 | Person operator+(Person &p1, int num) 36 | { 37 | Person temp; 38 | temp.m_A = p1.m_A + num; 39 | temp.m_B = p1.m_B + num; 40 | return temp; 41 | } 42 | 43 | void test01() 44 | { 45 | Person p1; 46 | p1.m_A = 10; 47 | p1.m_B = 10; 48 | Person p2; 49 | p2.m_A = 10; 50 | p2.m_B = 10; 51 | 52 | Person p3 = p1 + p2; 53 | // 成员函数重载本质调用 54 | // Person p3 = p1.operator+(p2); 55 | // 全局函数重载本质调用 56 | // Person p3 = operator+(p1, p2); 57 | 58 | cout << p3.m_A << endl; 59 | 60 | // 运算符重载也能发生函数重载 61 | Person p4 = p1 + 10; 62 | cout << p4.m_B << endl; 63 | } 64 | 65 | int main() 66 | { 67 | test01(); 68 | return 0; 69 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/32_类与对象_运算符重载_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 左移运算符重载:可以输出自定义数据类型 5 | 6 | class Person 7 | { 8 | friend ostream &operator<<(ostream &cout, Person &p); 9 | 10 | public: 11 | Person(int a, int b) : m_A(a), m_B(b) 12 | { 13 | } 14 | 15 | private: 16 | // 利用成员函数重载左移运算符 17 | // 不会利用成员函数重载<<运算符,因为无法实现cout在左侧 18 | // void operator<<(Person &p) 19 | // { 20 | // } 21 | int m_A; 22 | int m_B; 23 | }; 24 | 25 | // 只能利用全局函数重载左移运算符 26 | ostream &operator<<(ostream &cout, Person &p) // 本质 opeartor << (cout, p) 简化 cout << p 27 | { 28 | cout << "m_A = " << p.m_A << " m_B = " << p.m_B; 29 | return cout; 30 | } 31 | 32 | void test01() 33 | { 34 | Person p(10, 10); 35 | cout << p << endl; 36 | } 37 | 38 | int main() 39 | { 40 | test01(); 41 | return 0; 42 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/33_类与对象_运算符重载_03.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 递增运算符重载 5 | // 可以由此实现自己的整型数据(本课案例) 6 | 7 | class MyInteger 8 | { 9 | friend ostream &operator<<(ostream &cout, MyInteger myint); 10 | 11 | public: 12 | MyInteger() 13 | { 14 | m_Num = 0; 15 | } 16 | 17 | // 重载前置++运算符 18 | MyInteger &operator++() 19 | { 20 | m_Num++; 21 | return *this; 22 | } 23 | 24 | // 重载后置++运算符 25 | MyInteger operator++(int) // int 为占位参数,可以用于区分前置和后置递增 26 | { 27 | MyInteger temp = *this; 28 | m_Num++; 29 | return temp; 30 | } 31 | 32 | private: 33 | int m_Num; 34 | }; 35 | 36 | // 重载 << 运算符 37 | ostream &operator<<(ostream &cout, MyInteger myint) 38 | { 39 | cout << myint.m_Num; 40 | return cout; 41 | } 42 | 43 | void test01() 44 | { 45 | MyInteger myint; 46 | cout << ++myint << endl; 47 | } 48 | 49 | void test02() 50 | { 51 | MyInteger myint; 52 | cout << myint++ << endl; 53 | cout << myint << endl; 54 | } 55 | 56 | int main() 57 | { 58 | // test01(); 59 | test02(); 60 | return 0; 61 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/34_类与对象_运算符重载_04.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* 5 | C++ 编译器至少给一个类添加4个函数: 6 | 1.默认构造函数(无参,函数体为空) 7 | 2.默认析构函数(无参,函数体为空) 8 | 3.默认拷贝构造函数,对属性进行值拷贝 9 | 4.赋值运算符 opeartor= ,对属性进行值拷贝 10 | */ 11 | 12 | // 赋值运算符重载 13 | 14 | class Person 15 | { 16 | public: 17 | int *m_Age; 18 | 19 | Person(int age) 20 | { 21 | m_Age = new int(age); 22 | } 23 | 24 | ~Person() 25 | { 26 | if (m_Age != NULL) 27 | { 28 | delete m_Age; 29 | m_Age = NULL; 30 | } 31 | } 32 | 33 | // 重载赋值运算符 34 | Person &operator=(Person &p) 35 | { 36 | // 编译器提供浅拷贝,类似 m_Age = p.m_Age; 37 | 38 | // 应该先判断是否有属性在堆区,如有先释放干净,然后再深拷贝 39 | if (m_Age != NULL) 40 | { 41 | delete m_Age; 42 | m_Age = NULL; 43 | } 44 | m_Age = new int(*p.m_Age); 45 | return *this; 46 | } 47 | }; 48 | 49 | void test01() 50 | { 51 | Person p1(18); 52 | Person p2(20); 53 | Person p3(30); 54 | 55 | p3 = p2 = p1; // 赋值操作 56 | 57 | cout << *p1.m_Age << endl; 58 | cout << *p2.m_Age << endl; 59 | cout << *p3.m_Age << endl; 60 | } 61 | 62 | int main() 63 | { 64 | test01(); 65 | return 0; 66 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/35_类与对象_运算符重载_05.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 关系运算符重载:可以让两个自定义类型对象进行比较操作 5 | 6 | class Person 7 | { 8 | public: 9 | string m_Name; 10 | int m_Age; 11 | 12 | Person(string name, int age) : m_Name(name), m_Age(age) 13 | { 14 | } 15 | 16 | // 重载==号 17 | bool operator==(Person &p) 18 | { 19 | if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) 20 | { 21 | return true; 22 | } 23 | return false; 24 | } 25 | }; 26 | 27 | void test01() 28 | { 29 | Person p1("Tom", 18); 30 | Person p2("Tom", 18); 31 | 32 | if (p1 == p2) 33 | { 34 | cout << "p1 与 p2 相等" << endl; 35 | } 36 | else 37 | { 38 | cout << "p1 与 p2 不相等" << endl; 39 | } 40 | } 41 | 42 | int main() 43 | { 44 | test01(); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/36_类与对象_运算符重载_06.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 函数调用运算符重载 5 | // 由于重载后的使用方式非常像函数的调用,因此称为仿函数 6 | // 仿函数没有固定写法,非常灵活 7 | 8 | // 打印输出类 9 | class MyPrint 10 | { 11 | public: 12 | // 重载函数调用运算符 13 | void operator()(string test) 14 | { 15 | cout << test << endl; 16 | } 17 | }; 18 | 19 | void MyPrint02(string test) 20 | { 21 | cout << test << endl; 22 | } 23 | 24 | void test01() 25 | { 26 | MyPrint myPrint; 27 | myPrint("Hello World!"); // 由于重载后的使用方式非常像函数的调用,因此称为仿函数 28 | MyPrint02("Hello World!"); 29 | } 30 | 31 | // 加法类 32 | class MyAdd 33 | { 34 | public: 35 | int operator()(int num1, int num2) 36 | { 37 | return num1 + num2; 38 | } 39 | }; 40 | 41 | void test02() 42 | { 43 | MyAdd myAdd; 44 | int result = myAdd(100, 100); 45 | cout << result << endl; 46 | 47 | // 匿名函数对象 48 | cout << MyAdd()(100, 100) << endl; 49 | }; 50 | 51 | int main() 52 | { 53 | // test01(); 54 | test02(); 55 | return 0; 56 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/37_类与对象_继承_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 继承好处:减少重复代码 5 | // 语法: class 子类 : 继承方式 父类 6 | 7 | // 继承方式: 8 | // - 公共继承 9 | // - 保护继承 10 | // - 私有继承 11 | 12 | // 公共继承 13 | class Base1 14 | { 15 | public: 16 | int m_A; 17 | 18 | protected: 19 | int m_B; 20 | 21 | private: 22 | int m_C; 23 | }; 24 | 25 | class Child1 : public Base1 26 | { 27 | public: 28 | void func() 29 | { 30 | m_A = 10; // 父类中的公共权限成员到子类中依然是公共权限 31 | m_B = 10; // 父类中的保护权限成员到子类中依然是保护权限 32 | // m_C = 10; // 父类中的私有权限成员子类访问不到 33 | } 34 | }; 35 | 36 | void test01() 37 | { 38 | Child1 c1; 39 | c1.m_A = 100; 40 | // c1.m_B = 100; // 保护权限,类外访问不到 41 | } 42 | 43 | // 保护继承 44 | class Base2 45 | { 46 | public: 47 | int m_A; 48 | 49 | protected: 50 | int m_B; 51 | 52 | private: 53 | int m_C; 54 | }; 55 | 56 | class Child2 : protected Base2 57 | { 58 | public: 59 | void func() 60 | { 61 | m_A = 100; // 父类中公共成员,到子类中变为保护权限 62 | m_B = 100; // 父类中保护成员,到子类中变为保护权限 63 | // m_C = 100; // 父类中的私有权限成员子类访问不到 64 | } 65 | }; 66 | 67 | void test02() 68 | { 69 | Child2 c2; 70 | // c2.m_A = 1000; // 在 Child2 中 m_A 变为保护权限,类外访问不到 71 | // c2.m_B = 1000; 72 | } 73 | 74 | // 私有继承 75 | class Base3 76 | { 77 | public: 78 | int m_A; 79 | 80 | protected: 81 | int m_B; 82 | 83 | private: 84 | int m_C; 85 | }; 86 | 87 | class Child3 : private Base3 88 | { 89 | public: 90 | void func() 91 | { 92 | m_A = 100; // 父类中公共成员,到子类中变为私有成员 93 | m_B = 100; // 父类中保护成员,到子类中变为私有成员 94 | // m_C = 100; // 父类中的私有权限成员子类访问不到 95 | } 96 | }; 97 | 98 | void test03() 99 | { 100 | Child3 c3; 101 | // c3.m_A = 1000; // 私有权限,类外访问不到 102 | // c3.m_B = 1000; 103 | } 104 | 105 | class CChild : public Child3 106 | { 107 | public: 108 | void func() 109 | { 110 | // m_A = 1000; 111 | // m_B = 1000; 112 | } 113 | }; 114 | 115 | int main() 116 | { 117 | 118 | return 0; 119 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/38_类与对象_继承_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 继承中的对象模型 5 | 6 | class Base 7 | { 8 | public: 9 | int m_A; 10 | 11 | protected: 12 | int m_B; 13 | 14 | private: 15 | int m_C; // 私有成员只是被隐藏了,但还是会继承下去 16 | }; 17 | 18 | // 公共继承 19 | class Son : public Base 20 | { 21 | public: 22 | int m_D; 23 | }; 24 | 25 | void test01() 26 | { 27 | cout << "size of Son = " << sizeof(Son) << endl; 28 | // 父类中所有非静态成员属性都会被子类继承下去 29 | } 30 | 31 | int main() 32 | { 33 | test01(); 34 | return 0; 35 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/39_类与对象_继承_03.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 继承 - 构造和析构顺序 5 | // 构造:先构造父类,再构造子类 6 | // 析构:与构造顺序相反 7 | 8 | class Base 9 | { 10 | public: 11 | Base() 12 | { 13 | cout << "Base 构造函数!" << endl; 14 | } 15 | ~Base() 16 | { 17 | cout << "Base 析构函数!" << endl; 18 | } 19 | }; 20 | 21 | class Son : public Base 22 | { 23 | public: 24 | Son() 25 | { 26 | cout << "Son 构造函数!" << endl; 27 | } 28 | ~Son() 29 | { 30 | cout << "Son 析构函数!" << endl; 31 | } 32 | }; 33 | 34 | void test01() 35 | { 36 | // Base b; 37 | Son s; 38 | } 39 | 40 | int main() 41 | { 42 | test01(); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/40_类与对象_继承_04.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 继承 - 同名成员处理方式 5 | // 访问子类同名成员 直接访问即可 6 | // 访问父类同名成员 需要加作用域 7 | 8 | class Base 9 | { 10 | public: 11 | int m_A; 12 | 13 | Base() 14 | { 15 | m_A = 100; 16 | } 17 | 18 | void func() 19 | { 20 | cout << "Base - func() 调用" << endl; 21 | } 22 | 23 | void func(int a) 24 | { 25 | cout << "Base - func(int a) 调用" << endl; 26 | } 27 | }; 28 | 29 | class Son : public Base 30 | { 31 | public: 32 | int m_A; 33 | 34 | Son() 35 | { 36 | m_A = 200; 37 | } 38 | 39 | void func() 40 | { 41 | cout << "Son - func() 调用" << endl; 42 | } 43 | }; 44 | 45 | // 同名成员属性处理方式 46 | void test01() 47 | { 48 | Son s; 49 | cout << "Son m_A = " << s.m_A << endl; 50 | // 如果通过子类对象访问到父类中同名成员,需要加作用域 51 | cout << "Base m_A = " << s.Base::m_A << endl; 52 | } 53 | 54 | // 同名成员函数处理 55 | void test02() 56 | { 57 | Son s; 58 | s.func(); 59 | s.Base::func(); 60 | // 如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数 61 | // s.func(100); 62 | s.Base::func(100); 63 | } 64 | 65 | int main() 66 | { 67 | // test01(); 68 | test02(); 69 | return 0; 70 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/41_类与对象_继承_05.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 继承 - 同名静态成员处理方式 5 | // 访问子类同名成员 直接访问即可 6 | // 访问父类同名成员 需要加作用域 7 | 8 | class Base 9 | { 10 | public: 11 | static int m_A; 12 | 13 | static void func() 14 | { 15 | cout << "Base - func() 调用" << endl; 16 | } 17 | }; 18 | 19 | int Base::m_A = 100; 20 | 21 | class Son : public Base 22 | { 23 | public: 24 | static int m_A; 25 | 26 | static void func() 27 | { 28 | cout << "Son - func() 调用" << endl; 29 | } 30 | }; 31 | 32 | int Son::m_A = 200; 33 | 34 | // 同名静态成员属性处理方式 35 | void test01() 36 | { 37 | // 1、通过对象访问 38 | Son s; 39 | cout << "Son m_A = " << s.m_A << endl; 40 | // 如果通过子类对象访问到父类中同名成员,需要加作用域 41 | cout << "Base m_A = " << s.Base::m_A << endl; 42 | 43 | // 2、通过类名访问 44 | cout << "Son m_A " << Son::m_A << endl; 45 | // 第一个 :: 代表通过类名方式访问,第二个代表访问父类作用域下 46 | cout << "Base m_A " << Son::Base::m_A << endl; 47 | } 48 | 49 | // 同名静态成员函数处理 50 | void test02() 51 | { 52 | // 1、通过对象访问 53 | Son s; 54 | s.func(); 55 | s.Base::func(); 56 | // 如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数 57 | 58 | // 2、通过类名访问 59 | Son::func(); 60 | Son::Base::func(); 61 | } 62 | 63 | int main() 64 | { 65 | // test01(); 66 | test02(); 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/42_类与对象_继承_06.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 多继承:一个类继承多个类 5 | // 语法: class 子类名 : 继承方式 父类1, 继承方式 父类2 ... 6 | // 多继承可能会引发父类中有同名成员出现,需要加作用域区分 7 | // 实际开发中不建议用多继承 8 | 9 | class Base1 10 | { 11 | public: 12 | int m_A; 13 | 14 | Base1() 15 | { 16 | m_A = 100; 17 | } 18 | }; 19 | 20 | class Base2 21 | { 22 | public: 23 | int m_A; 24 | 25 | Base2() 26 | { 27 | m_A = 200; 28 | } 29 | }; 30 | 31 | // 子类 需要继承 Base1 和 Base2 32 | class Son : public Base1, public Base2 33 | { 34 | public: 35 | int m_C; 36 | int m_D; 37 | 38 | Son() 39 | { 40 | m_C = 300; 41 | m_D = 400; 42 | } 43 | }; 44 | 45 | void test01() 46 | { 47 | Son s; 48 | cout << "size of Son = " << sizeof(s) << endl; 49 | cout << s.Base1::m_A << endl; 50 | cout << s.Base2::m_A << endl; 51 | } 52 | 53 | int main() 54 | { 55 | test01(); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/43_类与对象_继承_07.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 菱形继承问题: 5 | // 两个派生类继承同一个基类,又有某个类同时继承这两个派生类 6 | 7 | // 利用虚继承可以解决菱形继承问题:在继承之前加上关键字 virtual 8 | 9 | class Animal // 虚基类 10 | { 11 | public: 12 | int m_Age; 13 | }; 14 | 15 | class Sheep : virtual public Animal 16 | { 17 | }; 18 | 19 | class Camel : virtual public Animal 20 | { 21 | }; 22 | 23 | class SheepCamel : public Sheep, public Camel 24 | { 25 | }; 26 | 27 | void test01() 28 | { 29 | SheepCamel sc; 30 | 31 | // sc.Sheep::m_Age = 10; 32 | // sc.Camel::m_Age = 8; 33 | sc.m_Age = 8; 34 | // 菱形继承时,两个父类有相同数据,需要加以作用域区分 35 | cout << "sc.Sheep::m_Age = " << sc.Sheep::m_Age << endl; 36 | cout << "sc.Camel::m_Age = " << sc.Camel::m_Age << endl; 37 | cout << sc.m_Age << endl; 38 | 39 | // m_Age数据存储一份即可,菱形继承导致数据有两份,造成资源浪费 40 | } 41 | 42 | int main() 43 | { 44 | test01(); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/44_类与对象_多态_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 多态 5 | // - 静态多态:函数重载和运算符重载,复用函数名 6 | // - 动态多态:派生类和虚函数实现运行时多态 7 | 8 | // 静态多态与动态多态区别: 9 | // 静态多态的函数地址早绑定 - 编译阶段确定函数地址 10 | // 动态多态的函数地址晚绑定 - 运行阶段确定函数地址 11 | 12 | class Animal 13 | { 14 | public: 15 | // 虚函数 16 | virtual void speak() 17 | { 18 | cout << "动物在说话" << endl; 19 | } 20 | }; 21 | 22 | class Cat : public Animal 23 | { 24 | public: 25 | // 重写:函数返回值、函数名、参数列表完全相同 26 | void speak() 27 | { 28 | cout << "猫在说话" << endl; 29 | } 30 | }; 31 | 32 | class Dog : public Animal 33 | { 34 | public: 35 | void speak() 36 | { 37 | cout << "狗在说话" << endl; 38 | } 39 | }; 40 | 41 | // 地址早绑定 在编译阶段确定函数地址 42 | // 如果想执行让猫说话,那么函数地址不能提前绑定,需要在运行阶段绑定(晚绑定) 43 | void doSpeak(Animal &animal) // Animal & animal = cat; 44 | { 45 | animal.speak(); 46 | } 47 | 48 | // 动态多态满足条件 49 | // 1、有继承关系 50 | // 2、子类重写父类的虚函数(重写:函数返回值、函数名、参数列表完全相同) 51 | 52 | // 动态多态使用:父类的引用/指针执行子类对象 53 | 54 | void test01() 55 | { 56 | Cat cat; 57 | doSpeak(cat); 58 | 59 | Dog dog; 60 | doSpeak(dog); 61 | } 62 | 63 | void test02() 64 | { 65 | Animal animal; 66 | cout << sizeof(animal) << endl; 67 | } 68 | 69 | int main() 70 | { 71 | // test01(); 72 | test02(); 73 | return 0; 74 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/46_类与对象_多态_03.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 纯虚函数与抽象类 5 | // 纯虚函数写法: virtual 返回值类型 函数名 (参数列表) = 0; 6 | 7 | // 当类中有了纯虚函数,该类也称为抽象类 8 | // 抽象类特点: 9 | // - 无法实例化对象 10 | // - 子类必须重写抽象类中的纯虚函数,否则也属于抽象类 11 | 12 | class Base 13 | { 14 | public: 15 | // 纯虚函数 16 | virtual void func() = 0; 17 | }; 18 | 19 | class Son : public Base 20 | { 21 | public: 22 | virtual void func() 23 | { 24 | cout << "func函数调用" << endl; 25 | } 26 | }; 27 | 28 | void test01() 29 | { 30 | Base *base = new Son; 31 | base->func(); 32 | } 33 | 34 | int main() 35 | { 36 | test01(); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/47_类与对象_多态_04.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 多态案例 - 制作饮品 5 | 6 | class AbstractDrinking 7 | { 8 | public: 9 | // 煮水 10 | virtual void Boil() = 0; 11 | 12 | // 冲泡 13 | virtual void Brew() = 0; 14 | 15 | // 倒入杯中 16 | virtual void PourInCup() = 0; 17 | 18 | // 加入辅料 19 | virtual void PutSomething() = 0; 20 | 21 | void makeDrink() 22 | { 23 | Boil(); 24 | Brew(); 25 | PourInCup(); 26 | PutSomething(); 27 | } 28 | }; 29 | 30 | // 制作咖啡 31 | class Coffee : public AbstractDrinking 32 | { 33 | public: 34 | // 煮水 35 | virtual void Boil() 36 | { 37 | cout << "煮水" << endl; 38 | } 39 | 40 | // 冲泡 41 | virtual void Brew() 42 | { 43 | cout << "冲泡咖啡" << endl; 44 | } 45 | 46 | // 倒入杯中 47 | virtual void PourInCup() 48 | { 49 | cout << "倒入杯中" << endl; 50 | } 51 | 52 | // 加入辅料 53 | virtual void PutSomething() 54 | { 55 | cout << "加入糖和牛奶" << endl; 56 | } 57 | }; 58 | 59 | // 制作茶 60 | class Tea : public AbstractDrinking 61 | { 62 | public: 63 | // 煮水 64 | virtual void Boil() 65 | { 66 | cout << "煮矿泉水" << endl; 67 | } 68 | 69 | // 冲泡 70 | virtual void Brew() 71 | { 72 | cout << "冲泡茶叶" << endl; 73 | } 74 | 75 | // 倒入杯中 76 | virtual void PourInCup() 77 | { 78 | cout << "倒入杯中" << endl; 79 | } 80 | 81 | // 加入辅料 82 | virtual void PutSomething() 83 | { 84 | cout << "加入枸杞" << endl; 85 | } 86 | }; 87 | 88 | void doWork(AbstractDrinking *abs) 89 | { 90 | abs->makeDrink(); 91 | delete abs; 92 | } 93 | 94 | void test01() 95 | { 96 | // 制作咖啡 97 | doWork(new Coffee); 98 | doWork(new Tea); 99 | } 100 | 101 | int main() 102 | { 103 | test01(); 104 | return 0; 105 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/48_类与对象_多态_05.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 虚析构和纯虚析构 5 | 6 | // 多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码 7 | // 解决方式:将父类中的析构函数改为虚析构或纯虚析构 8 | 9 | /* 10 | 虚析构和纯虚析构共性: 11 | - 可以解决父类指针释放子类对象 12 | - 都需要有具体的函数实现 13 | 14 | 虚析构和纯虚析构区别: 15 | - 如果是纯虚析构,该类属于抽象类,无法实例化对象 16 | 17 | 虚析构语法: 18 | virtual ~类名(){} 19 | 20 | 纯虚析构语法: 21 | virtual ~类名() = 0; 22 | 类名::~类名(){} 23 | */ 24 | 25 | class Animal 26 | { 27 | public: 28 | Animal() 29 | { 30 | cout << "Animal构造函数调用" << endl; 31 | } 32 | 33 | // 利用虚析构可以解决父类指针释放子类对象时不彻底的问题 34 | // virtual ~Animal() 35 | // { 36 | // cout << "Animal析构函数调用" << endl; 37 | // } 38 | 39 | // 纯虚析构 需要声明也需要实现 40 | // 有纯虚析构后,该类也属于抽象类,无法实例化对象 41 | virtual ~Animal() = 0; 42 | 43 | // 纯虚函数 只需声明 44 | virtual void speak() = 0; 45 | }; 46 | 47 | Animal::~Animal() 48 | { 49 | cout << "Animal纯虚析构函数调用" << endl; 50 | } 51 | 52 | class Cat : public Animal 53 | { 54 | public: 55 | Cat(string name) 56 | { 57 | cout << "Cat构造函数调用" << endl; 58 | m_Name = new string(name); 59 | } 60 | 61 | ~Cat() 62 | { 63 | if (m_Name != NULL) 64 | { 65 | cout << "Cat析构函数调用" << endl; 66 | delete m_Name; 67 | m_Name = NULL; 68 | } 69 | } 70 | 71 | virtual void speak() 72 | { 73 | cout << *m_Name << "猫在说话" << endl; 74 | } 75 | string *m_Name; 76 | }; 77 | 78 | void test01() 79 | { 80 | Animal *animal = new Cat("Tom"); 81 | animal->speak(); 82 | // 父类指针在析构时不会调用子类中析构函数, 83 | // 导致如果子类有堆区属性,则出现内存泄露 84 | delete animal; 85 | } 86 | 87 | int main() 88 | { 89 | test01(); 90 | return 0; 91 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/50_文件操作_文本文件_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | /* 6 | 写文件步骤如下: 7 | 1.包含头文件 8 | #include 9 | 2.创建流对象 10 | ofstream ofs 11 | 3.打开文件 12 | ofs.open("文件路径", 打开方式); 13 | 4.写数据 14 | ofs << "写入的数据"; 15 | 5.关闭文件 16 | ofs.close(); 17 | */ 18 | 19 | /* 20 | 打开方式详解 21 | ios::in 为读文件而打开文件 22 | ios::out 为写文件而打开文件 23 | ios::ate 初始位置:文件尾 24 | ios::app 追加方式写文件 25 | ios::trunc 如果文件存在,先删除再创建 26 | ios::binary 二进制方式 27 | */ 28 | 29 | // 文本文件 写文件 30 | 31 | void test01() 32 | { 33 | ofstream ofs; 34 | ofs.open("test.txt", ios::out); 35 | ofs << "测试文本" << endl; 36 | ofs.close(); 37 | } 38 | 39 | int main() 40 | { 41 | test01(); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/51_文件对象_文本文件_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // 文本文件 读文件 7 | 8 | void test01() 9 | { 10 | ifstream ifs; 11 | ifs.open("./test.txt", ios::in); 12 | if (!ifs.is_open()) 13 | { 14 | cout << "文件打开失败" << endl; 15 | return; 16 | } 17 | 18 | // 读数据 19 | 20 | // 第一种 21 | char buf[1024] = {0}; 22 | while (ifs >> buf) 23 | { 24 | cout << buf << endl; 25 | } 26 | 27 | // 第二种 28 | // char buf[1024] = {0}; 29 | // while (ifs.getline(buf, sizeof(buf))) 30 | // { 31 | // cout << buf << endl; 32 | // } 33 | 34 | // 第三种 35 | // string buf; 36 | // while (getline(ifs, buf)) 37 | // { 38 | // cout << buf << endl; 39 | // } 40 | 41 | // 第四种(不推荐) 42 | // char c; 43 | // while ((c = ifs.get()) != EOF) // EOF: end of file 44 | // { 45 | // cout << c; 46 | // } 47 | 48 | ifs.close(); 49 | } 50 | 51 | int main() 52 | { 53 | test01(); 54 | return 0; 55 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/52_文件操作_二进制文件_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 二进制文件 - 写文件 6 | 7 | class Person 8 | { 9 | public: 10 | char m_Name[64]; 11 | int m_Age; 12 | }; 13 | 14 | void test01() 15 | { 16 | ofstream ofs("person.txt", ios::out | ios::binary); 17 | // ofs.open("person.txt", ios::out | ios::binary); 18 | Person p = {"张三", 18}; 19 | ofs.write((const char *)&p, sizeof(Person)); 20 | ofs.close(); 21 | } 22 | 23 | int main() 24 | { 25 | test01(); 26 | return 0; 27 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/53_文件操作_二进制文件_02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 二进制文件 - 读文件 6 | 7 | class Person 8 | { 9 | public: 10 | char m_Name[64]; 11 | int m_Age; 12 | }; 13 | 14 | void test01() 15 | { 16 | ifstream ifs; 17 | ifs.open("person.txt", ios::in | ios::binary); 18 | if (!ifs.is_open()) 19 | { 20 | cout << "打开失败" << endl; 21 | return; 22 | } 23 | Person p; 24 | ifs.read((char *)&p, sizeof(Person)); 25 | cout << p.m_Name << " " << p.m_Age << endl; 26 | ifs.close(); 27 | } 28 | 29 | int main() 30 | { 31 | test01(); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/boss.cpp: -------------------------------------------------------------------------------- 1 | #include "boss.h" 2 | 3 | Boss::Boss(int id, string name, int dId) 4 | { 5 | this->m_Id = id; 6 | this->m_Name = name; 7 | this->m_DeptId = dId; 8 | } 9 | 10 | void Boss::showInfo() 11 | { 12 | cout << "职工编号: " << this->m_Id 13 | << "\t职工姓名: " << this->m_Name 14 | << "\t岗位: " << this->getDeptName() 15 | << endl; 16 | } 17 | 18 | string Boss::getDeptName() 19 | { 20 | return string("老板"); 21 | } 22 | -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/boss.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | #include "worker.h" 5 | 6 | // 老板类 7 | class Boss : public Worker 8 | { 9 | public: 10 | // 构造函数 11 | Boss(int id, string name, int dId); 12 | 13 | // 显示个人信息 14 | virtual void showInfo(); 15 | 16 | // 获取职工岗位名称 17 | virtual string getDeptName(); 18 | }; -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/empFile.txt: -------------------------------------------------------------------------------- 1 | 2 李四 1 2 | 1 张三 1 3 | 3 王五 2 -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/emplouee.cpp: -------------------------------------------------------------------------------- 1 | #include "employee.h" 2 | 3 | Employee::Employee(int id, string name, int dId) 4 | { 5 | this->m_Id = id; 6 | this->m_Name = name; 7 | this->m_DeptId = dId; 8 | } 9 | 10 | void Employee::showInfo() 11 | { 12 | cout << "职工编号: " << this->m_Id 13 | << "\t职工姓名: " << this->m_Name 14 | << "\t岗位: " << this->getDeptName() 15 | << endl; 16 | } 17 | 18 | string Employee::getDeptName() 19 | { 20 | return string("员工"); 21 | } 22 | -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/employee.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | #include "worker.h" 5 | 6 | // 员工类 7 | class Employee : public Worker 8 | { 9 | public: 10 | // 构造函数 11 | Employee(int id, string name, int dId); 12 | 13 | // 显示个人信息 14 | virtual void showInfo(); 15 | 16 | // 获取职工岗位名称 17 | virtual string getDeptName(); 18 | }; -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/main.cpp: -------------------------------------------------------------------------------- 1 | #include "workerManager.h" 2 | 3 | int main() 4 | { 5 | // 实例化管理者对象 6 | WorkerManager wm; 7 | int choice = 0; // 存储用户输入的选项 8 | while (true) 9 | { 10 | wm.Show_Menu(); 11 | cout << "输入您的选择:" << endl; 12 | cin >> choice; 13 | 14 | switch (choice) 15 | { 16 | case 0: // 退出系统 17 | wm.exitSystem(); 18 | break; 19 | case 1: // 添加职工 20 | wm.Add_Emp(); 21 | break; 22 | case 2: // 显示职工 23 | wm.Show_Emp(); 24 | break; 25 | case 3: // 删除职工 26 | wm.Del_Emp(); 27 | break; 28 | case 4: //修改职工 29 | wm.Mod_Emp(); 30 | break; 31 | case 5: //查找职工 32 | wm.Find_Emp(); 33 | break; 34 | case 6: //排序职工 35 | break; 36 | case 7: //清空文档 37 | wm.Clean_File(); 38 | break; 39 | default: 40 | // system("clear"); 41 | break; 42 | } 43 | } 44 | 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/manager.cpp: -------------------------------------------------------------------------------- 1 | #include "manager.h" 2 | 3 | Manager::Manager(int id, string name, int dId) 4 | { 5 | this->m_Id = id; 6 | this->m_Name = name; 7 | this->m_DeptId = dId; 8 | } 9 | 10 | void Manager::showInfo() 11 | { 12 | cout << "职工编号: " << this->m_Id 13 | << "\t职工姓名: " << this->m_Name 14 | << "\t岗位: " << this->getDeptName() 15 | << endl; 16 | } 17 | 18 | string Manager::getDeptName() 19 | { 20 | return string("经理"); 21 | } 22 | -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | #include "worker.h" 5 | 6 | // 员工类 7 | class Manager : public Worker 8 | { 9 | public: 10 | // 构造函数 11 | Manager(int id, string name, int dId); 12 | 13 | // 显示个人信息 14 | virtual void showInfo(); 15 | 16 | // 获取职工岗位名称 17 | virtual string getDeptName(); 18 | }; -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/worker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // 职工抽象类 7 | class Worker 8 | { 9 | public: 10 | // 显示个人信息 11 | virtual void showInfo() = 0; 12 | // 获取岗位名称 13 | virtual string getDeptName() = 0; 14 | 15 | int m_Id; // 职工编号 16 | string m_Name; // 职工姓名 17 | int m_DeptId; // 职工所在部门名称编号 18 | }; -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/54_综合案例_职工管理系统/workerManager.h: -------------------------------------------------------------------------------- 1 | #pragma once // 防止头文件重复包含 2 | #include 3 | #include 4 | #include "worker.h" 5 | #include "employee.h" 6 | #include "manager.h" 7 | #include "boss.h" 8 | using namespace std; 9 | 10 | #define FILENAME "empFile.txt" 11 | 12 | class WorkerManager 13 | { 14 | public: 15 | // 构造函数 16 | WorkerManager(); 17 | 18 | // 展示菜单 19 | void Show_Menu(); 20 | 21 | // 退出功能 22 | void exitSystem(); 23 | 24 | // 析构函数 25 | ~WorkerManager(); 26 | 27 | // 增加职工 28 | void Add_Emp(); 29 | 30 | // 保存文件 31 | void save(); 32 | 33 | // 统计文件中人数 34 | int get_EmpNum(); 35 | 36 | // 初始化员工 37 | void init_Emp(); 38 | 39 | // 显示职工 40 | void Show_Emp(); 41 | 42 | // 删除职工 43 | void Del_Emp(); 44 | 45 | // 按职工编号判断职工是否存在 46 | int IsExist(int id); 47 | 48 | // 修改职工 49 | void Mod_Emp(); 50 | 51 | // 查找职工 52 | void Find_Emp(); 53 | 54 | // 清空文件 55 | void Clean_File(); 56 | 57 | int m_EmpNum; // 记录文件中的人数个数 58 | Worker **m_EmpArray; // 员工数组的指针 59 | bool m_FileIsEmpty; // 文件是否为空的标志 60 | }; 61 | -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/person.txt: -------------------------------------------------------------------------------- 1 | 张三 -------------------------------------------------------------------------------- /Chapter_02_面向对象编程/test.txt: -------------------------------------------------------------------------------- 1 | 测试文本 2 | 第二行 3 | -------------------------------------------------------------------------------- /Chapter_03_模板/00_blank_templet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | 7 | return 0; 8 | } -------------------------------------------------------------------------------- /Chapter_03_模板/01_函数模板基本语法.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* 5 | 6 | 函数模板作用: 7 | 建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表 8 | 9 | 语法: 10 | template 11 | 函数声明或定义 12 | 13 | 语法解释: 14 | - template 声明创建模板 15 | - typename 表明其后的符号是一种数据类型,可以用class代替 16 | - T 通用的数据类型,名称可以更换,通常为大写字母 17 | 18 | */ 19 | 20 | template 21 | void mySwap(T &a, T &b) 22 | { 23 | T temp = a; 24 | a = b; 25 | b = temp; 26 | } 27 | 28 | void test01() 29 | { 30 | int a = 10; 31 | int b = 20; 32 | 33 | // 利用函数模板交换 34 | // 使用函数模板方式 35 | // 1、自动类型推导 36 | // mySwap(a, b); 37 | // 2、显式指定类型 38 | mySwap(a, b); 39 | 40 | cout << "a = " << a << endl; 41 | cout << "b = " << b << endl; 42 | } 43 | 44 | int main() 45 | { 46 | test01(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /Chapter_03_模板/02_函数模板注意事项.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 函数模板注意事项 5 | // 1.自动类型推导,必须推导出一致的数据类型T才可以使用 6 | // 2.模板必须要确定出T的数据类型,才可以使用 7 | 8 | template // typename 可以替换为 class 9 | void mySwap(T &a, T &b) 10 | { 11 | T temp = a; 12 | a = b; 13 | b = temp; 14 | } 15 | 16 | // 1.自动类型推导,必须推导出一致的数据类型T才可以使用 17 | void test01() 18 | { 19 | int a = 10; 20 | int b = 20; 21 | char c = 'c'; 22 | 23 | mySwap(a, b); // 正确 24 | // mySwap(a, c); // 错误 25 | 26 | cout << "a = " << a << endl; 27 | cout << "b = " << b << endl; 28 | } 29 | 30 | // 2.模板必须要确定出T的数据类型,才可以使用 31 | template 32 | void func() 33 | { 34 | cout << "func() 调用" << endl; 35 | } 36 | 37 | void test02() 38 | { 39 | // func(); // 错误 40 | func(); // 可以运行 41 | } 42 | 43 | int main() 44 | { 45 | test01(); 46 | test02(); 47 | return 0; 48 | } -------------------------------------------------------------------------------- /Chapter_03_模板/03_函数模板案例_数组排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序 5 | // 排序规则:降序,算法:选择排序 6 | // 分别利用char数组和int数组进行测试 7 | 8 | // 交换的函数模板 9 | template 10 | void mySwap(T &a, T &b) 11 | { 12 | T temp = a; 13 | a = b; 14 | b = temp; 15 | } 16 | 17 | // 排序函数模板 18 | template 19 | void mySort(T arr[], int len) 20 | { 21 | for (int i = 0; i < len; i++) 22 | { 23 | int max = i; 24 | for (int j = i + 1; j < len; j++) 25 | { 26 | if (arr[max] < arr[j]) 27 | { 28 | max = j; 29 | } 30 | } 31 | if (max != i) 32 | { 33 | mySwap(arr[max], arr[i]); 34 | } 35 | } 36 | } 37 | 38 | // 打印数组模板 39 | template 40 | void printArray(T arr[], int len) 41 | { 42 | for (int i = 0; i < len; i++) 43 | { 44 | cout << arr[i] << ""; 45 | } 46 | cout << endl; 47 | } 48 | 49 | void test01() 50 | { 51 | // 测试char数组 52 | char charArr[] = "badfec"; 53 | int ArrLen = sizeof(charArr) / sizeof(char); 54 | mySort(charArr, ArrLen); 55 | printArray(charArr, ArrLen); 56 | } 57 | 58 | void test02() 59 | { 60 | // 测试int数组 61 | int intArr[] = {5, 7, 3, 0, 4, 2, 9, 1, 8, 6}; 62 | int ArrLen = sizeof(intArr) / sizeof(int); 63 | mySort(intArr, ArrLen); 64 | printArray(intArr, ArrLen); 65 | } 66 | 67 | int main() 68 | { 69 | test01(); 70 | test02(); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /Chapter_03_模板/04_普通函数与函数模板区别.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* 5 | - 普通函数调用时可以发生自动类型转换(隐式类型转换) 6 | - 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换 7 | - 如果利用显式指定类型的方式,可以发生隐式类型转换 8 | */ 9 | 10 | int myAdd(int a, int b) 11 | { 12 | return a + b; 13 | } 14 | 15 | template 16 | T myAdd02(T a, T b) 17 | { 18 | return a + b; 19 | } 20 | 21 | void test01() 22 | { 23 | int a = 10; 24 | int b = 20; 25 | char c = 'c'; // 被隐式转换成了 int 类型的 99; 26 | cout << myAdd(a, b) << endl; 27 | cout << myAdd(a, c) << endl; // 也可以运行,会发生隐式类型转换 28 | } 29 | 30 | void test02() 31 | { 32 | int a = 10; 33 | int b = 20; 34 | char c = 'c'; 35 | // cout << myAdd02(a, c) << endl; // 报错 36 | cout << myAdd02(a, c) << endl; // 显式指定类型,可以运行,发生隐式类型转换 37 | } 38 | 39 | int main() 40 | { 41 | // test01(); 42 | test02(); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chapter_03_模板/05_普通函数与函数模板的调用规则.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* 5 | 1. 如果函数模板和普通函数都可以实现,优先调用普通函数 6 | 2. 可以通过空模板参数列表来强制调用函数模板 7 | 3. 函数模板也可以发生重载 8 | 4. 如果函数模板可以产生更好的匹配,优先调用函数模板 9 | */ 10 | 11 | void myPrint(int a, int b) 12 | { 13 | cout << "调用了普通函数" << endl; 14 | } 15 | 16 | template 17 | void myPrint(T a, T b) 18 | { 19 | cout << "调用了模板" << endl; 20 | } 21 | 22 | template 23 | void myPrint(T a, T b, T c) 24 | { 25 | cout << "调用了重载模板" << endl; 26 | } 27 | 28 | void test01() 29 | { 30 | int a = 10; 31 | int b = 20; 32 | // myPrint(a, b); 33 | 34 | // 通过空模板参数列表,强制调用函数模板 35 | myPrint<>(a, b); 36 | 37 | // 函数模板也可以发生重载 38 | // myPrint(a, b, 100); 39 | 40 | // 如果函数模板可以产生更好的匹配,优先调用函数模板 41 | char c1 = 'a'; 42 | char c2 = 'b'; 43 | myPrint(c1, c2); 44 | } 45 | 46 | int main() 47 | { 48 | test01(); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /Chapter_03_模板/06_模板的局限性.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 模板的局限性 6 | 7 | class Person 8 | { 9 | public: 10 | Person(string name, int age) 11 | { 12 | this->m_Name = name; 13 | this->m_Age = age; 14 | } 15 | string m_Name; 16 | int m_Age; 17 | }; 18 | 19 | // 对比两个数据是否相等的函数 20 | template 21 | bool myCompare(T &a, T &b) 22 | { 23 | if (a == b) 24 | { 25 | return true; 26 | } 27 | else 28 | { 29 | return false; 30 | } 31 | } 32 | 33 | void test01() 34 | { 35 | int a = 10; 36 | int b = 20; 37 | 38 | bool ret = myCompare(a, b); 39 | if (ret) 40 | { 41 | cout << "a == b" << endl; 42 | } 43 | else 44 | { 45 | cout << "a != b" << endl; 46 | } 47 | } 48 | 49 | // 利用具体化Person的版本实现代码,具体化优先调用 50 | template <> 51 | bool myCompare(Person &p1, Person &p2) 52 | { 53 | if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age) 54 | { 55 | return true; 56 | } 57 | else 58 | { 59 | return false; 60 | } 61 | } 62 | 63 | void test02() 64 | { 65 | Person p1("Tom", 10); 66 | Person p2("Tom", 10); 67 | 68 | bool ret = myCompare(p1, p2); 69 | if (ret) 70 | { 71 | cout << "p1 == p2" << endl; 72 | } 73 | else 74 | { 75 | cout << "p1 != p2" << endl; 76 | } 77 | } 78 | 79 | int main() 80 | { 81 | // test01(); 82 | test02(); 83 | return 0; 84 | } -------------------------------------------------------------------------------- /Chapter_03_模板/07_类模板基本语法.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* 5 | 类模板作用: 6 | - 建立一个通用类,类中的成员数据类型可以不具体制定,用一个虚拟的类型来代表 7 | 8 | 语法: 9 | template 10 | 类 11 | 12 | 解释: 13 | - temple 声明创建模板 14 | - class 表明其后的符号是一种数据类型,可以用typename代替 15 | - T 通用的数据类型,名称可以替换,通常为大写字母 16 | */ 17 | 18 | template 19 | class Person 20 | { 21 | public: 22 | Person(NameType name, AgeType age) 23 | { 24 | this->m_Name = name; 25 | this->m_Age = age; 26 | } 27 | 28 | void showPerson() 29 | { 30 | cout << "name: " << this->m_Name 31 | << "age: " << this->m_Age 32 | << endl; 33 | } 34 | 35 | NameType m_Name; 36 | AgeType m_Age; 37 | }; 38 | 39 | void test01() 40 | { 41 | Person p1("Tom", 10); 42 | p1.showPerson(); 43 | } 44 | 45 | int main() 46 | { 47 | test01(); 48 | return 0; 49 | } -------------------------------------------------------------------------------- /Chapter_03_模板/08_类模板与函数模板区别.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 类模板与函数模板区别: 5 | // 1.类模板没有自动类型推导的使用方式 6 | // 2.类模板在模板参数列表中可以有默认参数 7 | 8 | template // 可以有默认参数 9 | class Person 10 | { 11 | public: 12 | Person(NameType name, AgeType age) 13 | { 14 | this->m_Name = name; 15 | this->m_Age = age; 16 | } 17 | 18 | void showPerson() 19 | { 20 | cout << "name: " << this->m_Name 21 | << "\tage: " << this->m_Age 22 | << endl; 23 | } 24 | 25 | NameType m_Name; 26 | AgeType m_Age; 27 | }; 28 | 29 | // 1.类模板没有自动类型推导的使用方式(?) 30 | void test01() 31 | { 32 | // Person p("Tom", 20); 33 | 34 | // 因为已经有了默认参数,AgeType可以不显式指定数据类型 35 | Person p("Tom", 20); 36 | 37 | p.showPerson(); 38 | } 39 | 40 | int main() 41 | { 42 | test01(); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chapter_03_模板/09_类模板中成员函数创建时机.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 类模板中成员函数和普通类中成员函数创建时机有区别: 5 | // - 普通类中的成员函数一开始就可以创建 6 | // - 类模板中的成员函数在开始调用时才创建 7 | 8 | class Person1 9 | { 10 | public: 11 | void showPerson1() 12 | { 13 | cout << "Person1 show" << endl; 14 | } 15 | }; 16 | 17 | class Person2 18 | { 19 | public: 20 | void showPerson2() 21 | { 22 | cout << "Person2 show" << endl; 23 | } 24 | }; 25 | 26 | template 27 | class MyClass 28 | { 29 | public: 30 | T obj; 31 | 32 | // 类模板中的成员函数 33 | void func1() 34 | { 35 | obj.showPerson1(); 36 | } 37 | 38 | void func2() 39 | { 40 | obj.showPerson2(); 41 | } 42 | }; 43 | 44 | void test01() 45 | { 46 | MyClass m; 47 | m.func1(); 48 | 49 | // 注释下行后可以运行,因为 MyClass::func2()调用时才创建,不调用不创建,不出错 50 | // m.func2(); 51 | } 52 | 53 | int main() 54 | { 55 | test01(); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Chapter_03_模板/10_类模板对象做函数参数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 类模板对象做函数参数 5 | 6 | // 1.指定传入的类型 -- 直接显示对象的数据类型 7 | // 2.参数模板化 -- 将对象中的参数变为模板进行传递 8 | // 3.整个类模板化 -- 将这个对象类型模板化进行传递 9 | 10 | template 11 | class Person 12 | { 13 | public: 14 | Person(T1 name, T2 age) 15 | { 16 | this->m_Name = name; 17 | this->m_Age = age; 18 | } 19 | 20 | void showPerson() 21 | { 22 | cout << "name: " << this->m_Name 23 | << "\tage: " << this->m_Age 24 | << endl; 25 | } 26 | 27 | T1 m_Name; 28 | T2 m_Age; 29 | }; 30 | 31 | // 1.指定传入的类型 32 | void printPerson1(Person &p) 33 | { 34 | p.showPerson(); 35 | } 36 | 37 | void test01() 38 | { 39 | Person p("Tom", 20); 40 | printPerson1(p); 41 | } 42 | 43 | // 2.参数模板化 44 | template 45 | void printPerson2(Person &p) 46 | { 47 | p.showPerson(); 48 | cout << "T1 的数据类型为: " << typeid(T1).name() << endl; 49 | cout << "T2 的数据类型为: " << typeid(T2).name() << endl; 50 | } 51 | 52 | void test02() 53 | { 54 | Person p("Jerry", 19); 55 | printPerson2(p); 56 | } 57 | 58 | // 3.整个类模板化 59 | template 60 | void printPerson3(T &p) 61 | { 62 | p.showPerson(); 63 | cout << typeid(T).name() << endl; 64 | } 65 | 66 | void test03() 67 | { 68 | Person p("Max", 21); 69 | printPerson3(p); 70 | } 71 | 72 | int main() 73 | { 74 | test01(); 75 | test02(); 76 | test03(); 77 | return 0; 78 | } -------------------------------------------------------------------------------- /Chapter_03_模板/11_类模板与继承.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 当类模板遇到继承情况时,需要注意以下几点: 5 | // - 当子类继承的父类是一个类模板时,子类在声明的时候,要指出父类中T的类型 6 | // - 如果不指定,编译器无法给子类分配内存 7 | // - 如果想灵活指定出父类中T的类型,子类也需变为类模板 8 | 9 | template 10 | class Base 11 | { 12 | public: 13 | T m; 14 | }; 15 | 16 | // class Child : public Base {}; // 错误,必须知道父类中T的类型,才能继承给子类 17 | class Child : public Base 18 | { 19 | }; 20 | 21 | // 如果想灵活指定父类中T类型,子类也需要变类模板 22 | template 23 | class Child2 : public Base 24 | { 25 | public: 26 | Child2() 27 | { 28 | cout << "T1 的数据类型为 " << typeid(T1).name() << endl; 29 | cout << "T2 的数据类型为 " << typeid(T2).name() << endl; 30 | } 31 | T1 obj; 32 | }; 33 | 34 | void test01() 35 | { 36 | Child c1; 37 | } 38 | 39 | void test02() 40 | { 41 | Child2 c2; 42 | } 43 | 44 | int main() 45 | { 46 | test01(); 47 | test02(); 48 | return 0; 49 | } -------------------------------------------------------------------------------- /Chapter_03_模板/12_类模板成员函数类外实现.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 类模板成员函数类外实现 5 | 6 | template 7 | class Person 8 | { 9 | public: 10 | Person(T1 name, T2 age); 11 | void showPerson(); 12 | 13 | T1 m_Name; 14 | T2 m_Age; 15 | }; 16 | 17 | // 构造函数类外实现 18 | template 19 | Person::Person(T1 name, T2 age) 20 | { 21 | this->m_Name = name; 22 | this->m_Age = age; 23 | } 24 | 25 | // 成员函数类外实现 26 | template 27 | void Person::showPerson() 28 | { 29 | cout << "name: " << this->m_Name 30 | << "\tage: " << this->m_Age 31 | << endl; 32 | } 33 | 34 | void test01() 35 | { 36 | Person p("Tom", 20); 37 | p.showPerson(); 38 | } 39 | 40 | int main() 41 | { 42 | test01(); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chapter_03_模板/13_类模板的分文件编写/13_Person.cpp: -------------------------------------------------------------------------------- 1 | #include "13_Person.h" 2 | 3 | // 构造函数类外实现 4 | template 5 | Person::Person(T1 name, T2 age) 6 | { 7 | this->m_Name = name; 8 | this->m_Age = age; 9 | } 10 | 11 | // 成员函数类外实现 12 | template 13 | void Person::showPerson() 14 | { 15 | cout << "name: " << this->m_Name 16 | << "\tage: " << this->m_Age 17 | << endl; 18 | } -------------------------------------------------------------------------------- /Chapter_03_模板/13_类模板的分文件编写/13_Person.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | 5 | template 6 | class Person 7 | { 8 | public: 9 | Person(T1 name, T2 age); 10 | void showPerson(); 11 | T1 m_Name; 12 | T2 m_Age; 13 | }; -------------------------------------------------------------------------------- /Chapter_03_模板/13_类模板的分文件编写/13_Person.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | 5 | template 6 | class Person 7 | { 8 | public: 9 | Person(T1 name, T2 age); 10 | void showPerson(); 11 | T1 m_Name; 12 | T2 m_Age; 13 | }; 14 | 15 | // 构造函数类外实现 16 | template 17 | Person::Person(T1 name, T2 age) 18 | { 19 | this->m_Name = name; 20 | this->m_Age = age; 21 | } 22 | 23 | // 成员函数类外实现 24 | template 25 | void Person::showPerson() 26 | { 27 | cout << "name: " << this->m_Name 28 | << "\tage: " << this->m_Age 29 | << endl; 30 | } -------------------------------------------------------------------------------- /Chapter_03_模板/13_类模板的分文件编写/13_类模板的分文件编写.cpp: -------------------------------------------------------------------------------- 1 | // 第一种解决方式:直接包含源文件 2 | // #include "13_Person.cpp" 3 | 4 | // 第二种解决方式(常用):将.h和.cpp中的内容写在一起,将后缀名改为.hpp 5 | #include "13_Person.hpp" 6 | 7 | // 类模板分文件编写 8 | 9 | void test01() 10 | { 11 | Person p("Jerry", 18); 12 | p.showPerson(); 13 | } 14 | 15 | int main() 16 | { 17 | test01(); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /Chapter_03_模板/14_类模板与友元.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 类模板与友元 5 | // 通过全局函数打印Person信息 6 | 7 | template 8 | class Person; 9 | 10 | // 全局函数类外实现 11 | template 12 | void printPerson2(Person p) 13 | { 14 | cout << "姓名: " << p.m_Name 15 | << "\t年龄: " << p.m_Age 16 | << endl; 17 | } 18 | 19 | template 20 | class Person 21 | { 22 | // 全局函数,类内实现 23 | friend void printPerson(Person p) 24 | { 25 | cout << "姓名: " << p.m_Name 26 | << "\t年龄: " << p.m_Age 27 | << endl; 28 | } 29 | 30 | // 全局函数,类外实现 31 | // 加空模板参数列表 32 | // 需要让编译器提前知道该函数的存在 33 | friend void printPerson2<>(Person p); 34 | 35 | public: 36 | Person(T1 name, T2 age) 37 | { 38 | this->m_Name = name; 39 | this->m_Age = age; 40 | } 41 | 42 | private: 43 | T1 m_Name; 44 | T2 m_Age; 45 | }; 46 | 47 | // 全局函数类内实现的调用 48 | void test01() 49 | { 50 | Person p("Tom", 20); 51 | printPerson(p); 52 | } 53 | 54 | // 全局函数类外实现的调用 55 | void test02() 56 | { 57 | Person p("Jerry", 21); 58 | printPerson2(p); 59 | } 60 | 61 | int main() 62 | { 63 | // test01(); 64 | test02(); 65 | return 0; 66 | } -------------------------------------------------------------------------------- /Chapter_03_模板/15_类模板案例_自定义数组类/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MyArray.hpp" 2 | 3 | void test01() 4 | { 5 | MyArray arr1(5); 6 | // MyArray arr2(arr1); 7 | MyArray arr3(40); 8 | arr3 = arr1; 9 | } 10 | 11 | void printIntArray(MyArray &arr) 12 | { 13 | for (int i = 0; i < arr.getSize(); i++) 14 | { 15 | cout << arr[i] << endl; 16 | } 17 | } 18 | 19 | void test02() 20 | { 21 | MyArray arr(5); 22 | 23 | for (int i = 0; i < 5; i++) 24 | { 25 | // 利用尾插法向数组中插入数据 26 | arr.Push_Back(i); 27 | } 28 | cout << "-------尾删前-------" << endl; 29 | cout << "arr的打印输出为" << endl; 30 | printIntArray(arr); 31 | cout << "arr的容量为 " << arr.getCapacity() << endl; 32 | cout << "arr的大小为 " << arr.getSize() << endl; 33 | 34 | cout << "-------尾删后-------" << endl; 35 | arr.Pop_Back(); 36 | cout << "arr的打印输出为" << endl; 37 | printIntArray(arr); 38 | cout << "arr的容量为 " << arr.getCapacity() << endl; 39 | cout << "arr的大小为 " << arr.getSize() << endl; 40 | } 41 | 42 | // 测试自定义数据类型 43 | class Person 44 | { 45 | public: 46 | Person(){}; 47 | Person(string name, int age) 48 | { 49 | this->m_Name = name; 50 | this->m_Age = age; 51 | } 52 | string m_Name; 53 | int m_Age; 54 | }; 55 | 56 | void printPersonArray(MyArray &arr) 57 | { 58 | for (int i = 0; i < arr.getSize(); i++) 59 | { 60 | cout << "姓名 " << arr[i].m_Name 61 | << "\t年龄" << arr[i].m_Age 62 | << endl; 63 | } 64 | } 65 | 66 | void test03() 67 | { 68 | MyArray arr(10); 69 | 70 | Person p1("张三", 20); 71 | Person p2("李四", 22); 72 | Person p3("王五", 21); 73 | Person p4("周六", 19); 74 | 75 | // 将数据插入到数组中 76 | arr.Push_Back(p1); 77 | arr.Push_Back(p2); 78 | arr.Push_Back(p3); 79 | arr.Push_Back(p4); 80 | 81 | printPersonArray(arr); 82 | } 83 | 84 | int main() 85 | { 86 | // test01(); 87 | // test02(); 88 | test03(); 89 | return 0; 90 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/00_blank_templet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | 7 | return 0; 8 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/01_STL基本概念.md: -------------------------------------------------------------------------------- 1 | # STL 基本概念 2 | 3 | - STL(Standard Template Library, 标准模板库) 4 | - STL从广义上分为:容器(container)、算法(alorithm)、迭代器(iterator) 5 | - 容器和算法之间通过迭代器进行无缝连接 6 | - STL几乎所有代码都采用了模板类或者模板函数 7 | 8 | ## STL 六大组件 9 | 10 | STL大体分为六大组件,分别为:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器 11 | 12 | 1. 容器:各种数据结构,如 vector, list, deque, set, map 等,用来存放数据 13 | 2. 算法:各种常用的算法,如 sort, find, copy, for_each 等 14 | 3. 迭代器:容器与算法之间的胶合剂 15 | 4. 仿函数:行为类似函数,可作为算法的某种策略 16 | 5. 适配器:用来修饰容器或者仿函数或迭代器接口 17 | 6. 空间配置器:负责空间的配置与管理 18 | 19 | ## 具体 20 | 21 | ### 容器:置物之所也 22 | 23 | STL容器就是将运用最广泛的一些数据结构实现出来 24 | 25 | 常用的数据结构:数组、列表、树、栈、队列、集合、映射表等 26 | 27 | 这些容器分为序列式容器和关联式容器两种: 28 | 29 | - 序列式容器:强调值的排序 30 | - 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系 31 | 32 | ### 算法:问题之解法也 33 | 34 | 通过有限的步骤解决逻辑或数学上的问题,这门学科称之为算法(Algorithms) 35 | 36 | 算法分为:质变算法和非质变算法 37 | 38 | - 质变算法:指运算过程中会更改区间内的元素的内容。如拷贝、替换、删除等 39 | - 非质变算法:指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等 40 | 41 | ### 迭代器:容器和算法之间的粘合剂 42 | 43 | 提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表现方式 44 | 每个容器都有自己专属的迭代器 45 | 迭代器的使用非常类似指针 46 | 47 | 迭代器种类: 48 | 49 | | 种类 | 功能 | 支持运算 | 50 | | -------------- | -------------------------------------------------------- | ---------------------------------------- | 51 | | 输入迭代器 | 对数据的只读访问 | 只读,支持 ++、==、!= | 52 | | 输出迭代器 | 对数据的只写访问 | 只写,支持 ++ | 53 | | 前向迭代器 | 读写操作,并能向前推进迭代器 | 读写,支持 ++、==、!= | 54 | | 双向迭代器 | 读写操作,并能向前和向后操作 | 读写,支持 ++、-- | 55 | | 随机访问迭代器 | 读写操作,可以以跳跃的方式访问任何数据,功能最强的迭代器 | 读写,支持 ++、--、[n]、-n、<、<=、>、>= | 56 | -------------------------------------------------------------------------------- /Chapter_04_STL_容器/02_vector存放内置数据类型.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // 容器 vector 7 | // 算法 for_each 8 | // 迭代器 vector::iterator 9 | 10 | // vector容器存放内置数据类型 (类似数组) 11 | 12 | void myPrint(int val) 13 | { 14 | cout << val << endl; 15 | } 16 | 17 | void test01() 18 | { 19 | // 创建了一个vector容器 20 | vector v; 21 | 22 | // 向容器中插入数据 23 | v.push_back(10); 24 | v.push_back(20); 25 | v.push_back(30); 26 | v.push_back(40); 27 | 28 | // 通过迭代器访问容器中的数据 29 | vector::iterator itBegin = v.begin(); // 起始迭代器,指向容器中第一个元素 30 | vector::iterator itEnd = v.end(); // 结束迭代器,指向容器中最后一个元素的下一位置 31 | 32 | // 第一种遍历方式 33 | // while (itBegin != itEnd) 34 | // { 35 | // cout << *itBegin << endl; 36 | // itBegin++; 37 | // } 38 | 39 | // 第二种遍历方式 40 | // for (vector::iterator it = v.begin(); it != v.end(); it++) 41 | // { 42 | // cout << *it << endl; 43 | // } 44 | 45 | // 第三种遍历方式:利用 STL 提供的遍历算法 46 | for_each(v.begin(), v.end(), myPrint); 47 | } 48 | 49 | int main() 50 | { 51 | test01(); 52 | return 0; 53 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/03_vector存放自定义数据类型.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // vector容器中存放自定义数据类型 6 | 7 | class Person 8 | { 9 | public: 10 | Person(string name, int age) 11 | { 12 | this->m_Name = name; 13 | this->m_Age = age; 14 | } 15 | 16 | string m_Name; 17 | int m_Age; 18 | }; 19 | 20 | void test01() 21 | { 22 | vector v; 23 | Person p1("a", 20); 24 | Person p2("b", 21); 25 | Person p3("c", 22); 26 | Person p4("d", 23); 27 | Person p5("e", 23); 28 | 29 | // 向容器中添加数据 30 | v.push_back(p1); 31 | v.push_back(p2); 32 | v.push_back(p3); 33 | v.push_back(p4); 34 | v.push_back(p5); 35 | 36 | // 遍历容器中的数据 37 | for (vector::iterator it = v.begin(); it != v.end(); it++) 38 | { 39 | cout << "姓名: " << (*it).m_Name 40 | << "\t年龄" << it->m_Age 41 | << endl; 42 | } 43 | } 44 | 45 | // 存放自定义数据类型 指针 46 | void test02() 47 | { 48 | vector v; 49 | Person p1("a", 20); 50 | Person p2("b", 21); 51 | Person p3("c", 22); 52 | Person p4("d", 23); 53 | Person p5("e", 23); 54 | 55 | // 向容器中添加数据 56 | v.push_back(&p1); 57 | v.push_back(&p2); 58 | v.push_back(&p3); 59 | v.push_back(&p4); 60 | v.push_back(&p5); 61 | 62 | // 遍历容器 63 | for (vector::iterator it = v.begin(); it != v.end(); it++) 64 | { 65 | cout << "姓名: " << (*it)->m_Name 66 | << "\t年龄" << (*it)->m_Age 67 | << endl; 68 | } 69 | } 70 | 71 | int main() 72 | { 73 | // test01(); 74 | test02(); 75 | return 0; 76 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/04_vector容器嵌套容器.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | void test01() 6 | { 7 | vector> v; 8 | 9 | // 创建内层容器 10 | vector v1; 11 | vector v2; 12 | vector v3; 13 | vector v4; 14 | 15 | // 向内层容器中添加数据 16 | for (int i = 0; i < 4; i++) 17 | { 18 | v1.push_back(i + 1); 19 | v2.push_back(i + 2); 20 | v3.push_back(i + 3); 21 | v4.push_back(i + 4); 22 | } 23 | 24 | // 将内层容器插入到外层容器中 25 | v.push_back(v1); 26 | v.push_back(v2); 27 | v.push_back(v3); 28 | v.push_back(v4); 29 | 30 | // 通过外层容器,遍历所有数据 31 | for (vector>::iterator it = v.begin(); it != v.end(); it++) 32 | { 33 | for (vector::iterator vit = (*it).begin(); vit != (*it).end(); vit++) 34 | { 35 | cout << *vit << " "; 36 | } 37 | cout << endl; 38 | } 39 | } 40 | 41 | int main() 42 | { 43 | test01(); 44 | return 0; 45 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/05_string_构造函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | /* 6 | string 与 char * 的区别: 7 | - char * 是一个指针 8 | - string 是一个类,类内部封装了char*,管理字符串,是一个char*类型的容器 9 | 10 | string 特点: 11 | - 封装了查找(find)、拷贝(copy)、删除(delete)、替换(replace)、插入(insert)等成员方法 12 | - string管理char*所分配的内存,不用担心复制越界取值越界等 13 | 14 | 构造函数: 15 | - string(); //创建一个空的字符串。例如 string str; 16 | string(const char* s); // 使用字符串s初始化 17 | - string(const string& str); // 使用一个string对象初始化另一个string对象 18 | - string(int n, char c); // 使用n个字符串c初始化 19 | */ 20 | 21 | void test01() 22 | { 23 | string s1; //默认构造 24 | 25 | const char *str = "hello world"; 26 | string s2(str); 27 | cout << "s2 = " << s2 << endl; 28 | 29 | string s3(s2); 30 | cout << "s3 = " << s3 << endl; 31 | 32 | string s4(10, 'a'); 33 | cout << "s4 = " << s4 << endl; 34 | } 35 | 36 | int main() 37 | { 38 | test01(); 39 | return 0; 40 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/06_string_赋值操作.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | /* 6 | 7 | - string& operator= (const char* s); // 将char* 类型字符串赋值给当前的字符串 8 | - string& operator= (const string &s); // 将字符串s赋给当前的字符串 9 | - string& operator= (char c); // 将字符赋值给当前的字符串 10 | - string& assign(const char *s); // 将字符串s赋值给当前的字符串 11 | - string& assign(const char *s, int n); // 将字符串s的前n个字符赋给当前的字符串 12 | - string& assign(const string &s); // 将字符串s赋给当前字符串 13 | - string& assign(int n, char c); // 用n个字符c给当前字符串赋值 14 | 15 | */ 16 | 17 | void test01() 18 | { 19 | string str1; 20 | str1 = "Hello world!"; 21 | cout << "str1 = " << str1 << endl; 22 | 23 | string str2; 24 | str2 = str1; 25 | cout << "str2 = " << str2 << endl; 26 | 27 | string str3; 28 | str3 = 'a'; 29 | cout << "str3 = " << str3 << endl; 30 | 31 | string str4; 32 | str4.assign("Hello CPP!"); 33 | cout << "str4 = " << str4 << endl; 34 | 35 | string str5; 36 | str5.assign("Hello CPP! Something very very long.", 5); 37 | cout << "str5 = " << str5 << endl; 38 | 39 | string str6; 40 | str6.assign(str5); 41 | cout << "str6 = " << str6 << endl; 42 | 43 | string str7; 44 | str7.assign(10, 'm'); 45 | cout << "str7 = " << str7 << endl; 46 | } 47 | 48 | int main() 49 | { 50 | test01(); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/07_string_字符串拼接.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | /* 6 | 7 | - string& operator+= (const char* str); // 重载 += 操作符 8 | - string& operator+= (const char c); // 重载 += 操作符 9 | - string& operator+= (const string& str); // 重载 += 操作符 10 | - string& append(const char *s); // 将字符串 s 连接到当前字符串末尾 11 | - string& append(const char *s, int n); // 将字符串 s 的前n个字符连接到当前字符串结尾 12 | - string& append(const string &s); // 同 operator+= (const string& str); 13 | - string& append(const string &s, int pos, int n); // 将字符串 s 中从pos开始的n个字符连接到字符串的结尾 14 | 15 | */ 16 | 17 | void test01() 18 | { 19 | string str1 = "https://muzing"; 20 | str1 += ".top"; 21 | cout << "str1 = " << str1 << endl; 22 | 23 | str1 += '/'; 24 | cout << "str1 = " << str1 << endl; 25 | 26 | string str2 = "about/"; 27 | str1 += str2; 28 | cout << "str1 = " << str1 << endl; 29 | 30 | string str3 = "https://"; 31 | str3.append("domm."); 32 | str3.append("muzing.top", 6); 33 | string str4 = ".top"; 34 | str3.append(str4); 35 | str3.append(str2, 5, 1); // 从第5个字符开始截取,取长度为1的 36 | cout << "str3 = " << str3 << endl; 37 | } 38 | 39 | int main() 40 | { 41 | test01(); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/08_string_查找与替换.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // string 的查找与替换 6 | 7 | /* 8 | 9 | - int find(const string& str, int pos = 0) const; // 查找str第一次出现的位置,从pos开始查找 10 | - int find(const char* s, int pos = 0) const; // 查找s第一次出现的位置,从pos开始查找 11 | - int find(const char* s, int pos, int n) const; // 查找s的前n个字符第一次出现的位置,从pos开始 12 | - int find(const char c, int pos = 0) const; // 查找字符c第一次出现位置 13 | - int rfind(const string& str, int pos = npos) const; // 查找str最后一次位置,从pos开始查找 14 | - int rfind(const char* s, int pos = npos) const; // 查找s最后一次出现位置,从pos开始查找 15 | - int rfind(const char* s, int pos, int n) const; // 查找s的前n个字符最后一次出现位置,从pos开始查找 16 | - int rfind(const char c, int pos = 0) const; // 查找字符c最后一次出现位置 17 | - string& replace(int pos, int n, const string& str); // 替换从pos开始n个字符为字符串str 18 | - string& replace(int pos, int n, const char* s); // 替换从pos开始的n个字符为字符串s 19 | 20 | */ 21 | 22 | // 查找 23 | void test01() 24 | { 25 | string str1 = "abcdefgde"; 26 | int pos = str1.find("de"); 27 | // int pos = str1.find("df"); // 未找到,返回 -1 28 | if (pos == -1) 29 | { 30 | cout << "未找到字符串" << endl; 31 | } 32 | else 33 | { 34 | cout << "找到字符串, pos = " << pos << endl; 35 | } 36 | 37 | // rfind (从右向左查找) 38 | pos = str1.rfind("de"); 39 | cout << "pos = " << pos << endl; 40 | } 41 | 42 | // 替换 43 | void test02() 44 | { 45 | string str1 = "abcdefg"; 46 | // 从 1 起的 3 个字符替换为 11111 47 | str1.replace(1, 3, "11111"); 48 | cout << str1 << endl; 49 | } 50 | 51 | int main() 52 | { 53 | test01(); 54 | test02(); 55 | return 0; 56 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/09_string_字符串比较.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 字符串比较 6 | /* 7 | 8 | 字符串比较是按字符的ASCII码进行对比 9 | 10 | - = 返回 0 11 | - > 返回 1 12 | - < 返回 -1 13 | 14 | - int compare(const string &s) const; // 与字符串s比较 15 | - int compare(const char *s) const; // 与字符串s比较 16 | */ 17 | 18 | void test01() 19 | { 20 | // string str1 = "hello"; 21 | string str1 = "xello"; 22 | // string str2 = "hello"; 23 | string str2 = "zello"; 24 | 25 | if (str1.compare(str2) == 0) 26 | { 27 | cout << "str1 等于 str2" << endl; 28 | } 29 | else if (str1.compare(str2) > 0) 30 | { 31 | cout << "str1 大于 str2" << endl; 32 | } 33 | else if (str1.compare(str2) < 0) 34 | { 35 | cout << "str1 小于 str2" << endl; 36 | } 37 | } 38 | 39 | int main() 40 | { 41 | test01(); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/10_string_字符存取.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // string字符存取 6 | 7 | // - char& operator[] (int n); // 通过[]方式取字符 8 | // - char& at(int n); // 通过at方法获取字符 9 | 10 | void test01() 11 | { 12 | string str = "hello"; 13 | // cout << "str = " << str << endl; 14 | 15 | // 通过[]访问单个字符 16 | for (int i = 0; i < str.size(); i++) 17 | { 18 | cout << str[i] << " "; 19 | } 20 | cout << endl; 21 | 22 | // 通过at()访问单个字符 23 | for (int i = 0; i < str.size(); i++) 24 | { 25 | cout << str.at(i) << " "; 26 | } 27 | cout << endl; 28 | 29 | // 修改单个字符 30 | str[0] = 'x'; // xello 31 | str.at(1) = 'y'; // xyllo 32 | cout << "str = " << str << endl; 33 | } 34 | 35 | int main() 36 | { 37 | test01(); 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/11_string_字符串插入与删除.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 字符串插入与删除 6 | 7 | /* 8 | - string& insert(int pos, const char* s); // 插入字符串 9 | - string& insert(int pos, const string& str); // 插入字符串 10 | - string& insert(int pos, int n, char c); // 在指定位置插入n个字符c 11 | - string& erase(int pos, int n = npos); // 删除从pos开始的n个字符 12 | */ 13 | 14 | void test01() 15 | { 16 | string str = "hello"; 17 | 18 | // 插入 19 | str.insert(1, "111"); // h111ello 20 | cout << "str = " << str << endl; 21 | 22 | // 删除 23 | str.erase(1, 3); // hello 24 | cout << "str = " << str << endl; 25 | } 26 | 27 | int main() 28 | { 29 | test01(); 30 | return 0; 31 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/12_string_子串获取.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // string 子串获取 6 | 7 | // 返回由pos开始的n个字符组成的字符串 8 | // string substr(int pos = 0, int n = npos) const; 9 | 10 | void test01() 11 | { 12 | string str = "abcdefg"; 13 | string subStr = str.substr(1, 3); 14 | 15 | cout << "subStr = " << subStr << endl; 16 | } 17 | 18 | // 实用操作 19 | void test02() 20 | { 21 | string email = "muzi2001@foxmial.com"; 22 | // 从邮件地址中获取用户名信息 23 | int pos = email.find("@"); 24 | string userName = email.substr(0, pos); 25 | cout << userName << endl; 26 | } 27 | 28 | int main() 29 | { 30 | test01(); 31 | test02(); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/13_vector_构造函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // vector 基本概念与构造函数 6 | 7 | /* 8 | vector 基本概念 9 | vector 数据结构与数组非常相似,也称为单端数组。 10 | 不同之处在于数组是静态空间,vector可以动态扩展 11 | 12 | 动态扩展:并非在原空间之后续接新空间,而是找更大的内存空间,然后将原有的数据拷贝到新空间,释放原空间 13 | 14 | vector容器的迭代器支持随机访问 15 | */ 16 | 17 | /* 18 | vector 构造函数 19 | 20 | - vector v; // 采用模板实现类实现,默认构造函数 21 | - vector(v.begin(), v.end()); // 将 v[begin(), end()) 区间中的元素拷贝给本身 22 | - vector(n, elem); // 构造函数将 n 个 elem 拷贝给本身 23 | - vector(const vector &vec); // 拷贝构造函数 24 | */ 25 | 26 | void printVector(vector &v) 27 | { 28 | for (vector::iterator it = v.begin(); it != v.end(); it++) 29 | { 30 | cout << *it << " "; 31 | } 32 | cout << endl; 33 | } 34 | 35 | void test01() 36 | { 37 | // 默认构造:无参构造 38 | vector v1; 39 | for (int i = 0; i < 10; i++) 40 | { 41 | v1.push_back(i); 42 | } 43 | printVector(v1); 44 | 45 | // 通过区间方式进行构造 46 | vector v2(v1.begin(), v1.end()); 47 | printVector(v2); 48 | 49 | // n个elem方式构造 50 | vector v3(10, 100); 51 | printVector(v3); 52 | 53 | // 拷贝构造 54 | vector v4(v3); 55 | printVector(v4); 56 | } 57 | 58 | int main() 59 | { 60 | test01(); 61 | return 0; 62 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/14_vector_赋值操作.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // vector 赋值操作 6 | 7 | /* 8 | - vector& operator= (const vector &vec); // 重载 = 运算符 9 | - assign(beg, end); // 将 [beg, end) 区间中的数据拷贝赋值给本身 10 | - assign(n ,elem); // 将 n 个 elem 拷贝赋值给本身 11 | */ 12 | 13 | void printVector(vector &v) 14 | { 15 | for (vector::iterator it = v.begin(); it != v.end(); it++) 16 | { 17 | cout << *it << " "; 18 | } 19 | cout << endl; 20 | } 21 | 22 | void test01() 23 | { 24 | vector v1; 25 | for (int i = 0; i < 10; i++) 26 | { 27 | v1.push_back(i); 28 | } 29 | printVector(v1); 30 | 31 | // operator= 32 | vector v2; 33 | v2 = v1; 34 | printVector(v2); 35 | 36 | // assign 37 | vector v3; 38 | v3.assign(v1.begin(), v1.end()); 39 | printVector(v3); 40 | 41 | // n 个 elem 42 | vector v4; 43 | v4.assign(10, 100); 44 | printVector(v4); 45 | } 46 | 47 | int main() 48 | { 49 | test01(); 50 | return 0; 51 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/15_vector_容量与大小.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // vector 容量与大小 6 | 7 | /* 8 | - empty(); // 判断容器是否为空 9 | - capacity(); // 容器的容量 10 | - size(); // 返回容器中元素的个数 11 | - resize(int num); // 重新指定容器的长度为num,若容器变长,则以默认值填充新位置;若变短,则末尾超出容器长度的元素被删除 12 | - resize(int num, elem); // 重新指定容器的长度为num,若变长则以elem填充新位置;若变短则删末尾超出 13 | */ 14 | 15 | void printVector(vector &v) 16 | { 17 | for (vector::iterator it = v.begin(); it != v.end(); it++) 18 | { 19 | cout << *it << " "; 20 | } 21 | cout << endl; 22 | } 23 | 24 | void test01() 25 | { 26 | vector v1; 27 | for (int i = 0; i < 10; i++) 28 | { 29 | v1.push_back(i); 30 | } 31 | printVector(v1); 32 | 33 | if (v1.empty()) 34 | { 35 | cout << "v1 为空" << endl; 36 | } 37 | else 38 | { 39 | cout << "v1 不为空" << endl; 40 | cout << "v1 容量为 " << v1.capacity() << endl; 41 | cout << "v1 大小为 " << v1.size() << endl; 42 | } 43 | 44 | // 重新指定大小 45 | // v1.resize(15); // 如果新size大于原来的,默认用0填充 46 | v1.resize(15, 10); // 也可以指定用elem填充 47 | printVector(v1); 48 | 49 | v1.resize(5); // 如果新size小于原来的,超出的部分会被删除 50 | printVector(v1); 51 | } 52 | 53 | int main() 54 | { 55 | test01(); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/16_vector_插入与删除.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // vector 插入与删除 6 | 7 | /* 8 | - push_back(ele); // 尾部插入元素ele 9 | - pop_back(); // 删除最后一个元素 10 | - insert(const_iterator pos, ele); // 迭代器指向位置pos插入元素ele 11 | - insert(const_iterator pos, int count,ele); // 迭代器指向位置pos插入count个元素ele 12 | - erase(const_iterator pos); // 删除迭代器指向的元素 13 | - erase(const_iterator start, const_tierator end); // 删除迭代器从start到end之间的元素 14 | - ckear(); // 删除容器中所有元素 15 | */ 16 | 17 | void printVector(vector &v) 18 | { 19 | for (vector::iterator it = v.begin(); it != v.end(); it++) 20 | { 21 | cout << *it << " "; 22 | } 23 | cout << endl; 24 | } 25 | 26 | void test01() 27 | { 28 | vector v1; 29 | // 尾插 30 | v1.push_back(10); 31 | v1.push_back(20); 32 | v1.push_back(30); 33 | v1.push_back(40); 34 | 35 | printVector(v1); 36 | 37 | // 尾删 38 | v1.pop_back(); 39 | printVector(v1); 40 | 41 | // 插入(第一个参数是迭代器) 42 | v1.insert(v1.begin(), 100); 43 | printVector(v1); 44 | v1.insert(v1.begin(), 2, 1000); 45 | printVector(v1); 46 | 47 | // 删除(参数为迭代器) 48 | v1.erase(v1.begin()); 49 | printVector(v1); 50 | 51 | // 删除区间 52 | // v1.erase(v1.begin(), v1.end()); 53 | 54 | // 清空 55 | v1.clear(); 56 | printVector(v1); 57 | } 58 | 59 | int main() 60 | { 61 | test01(); 62 | return 0; 63 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/17_vector_数据存取.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // vector 数据存取 6 | 7 | /* 8 | - at(int idx); // 返回索引idx所指的数据 9 | - operator[]; // 返回索引idx所指的数据 10 | - front(); // 返回容器中第一个数据元素 11 | - back(); // 返回容器中最后一个数据元素 12 | */ 13 | 14 | void test01() 15 | { 16 | vector v1; 17 | for (int i = 0; i < 10; i++) 18 | { 19 | v1.push_back(i); 20 | } 21 | 22 | // 利用operator[]访问vector中元素 23 | for (int i = 0; i < v1.size(); i++) 24 | { 25 | cout << v1[i] << " "; 26 | } 27 | cout << endl; 28 | 29 | // 利用at访问元素 30 | for (int i = 0; i < v1.size(); i++) 31 | { 32 | cout << v1.at(i) << " "; 33 | } 34 | cout << endl; 35 | 36 | // 容器中第一个数据元素 37 | cout << "v1 的首元素为 " << v1.front() << endl; 38 | 39 | // 容器中最后一个元素 40 | cout << "v1 的末元素为 " << v1.back() << endl; 41 | } 42 | 43 | int main() 44 | { 45 | test01(); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/18_vector_互换容器.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // vector 互换容器 6 | 7 | // swap(vec); // 将vec与本身的元素互换 8 | 9 | void printVector(vector &v) 10 | { 11 | for (vector::iterator it = v.begin(); it != v.end(); it++) 12 | { 13 | cout << *it << " "; 14 | } 15 | cout << endl; 16 | } 17 | 18 | // 基本使用 19 | void test01() 20 | { 21 | vector v1; 22 | for (int i = 0; i < 10; i++) 23 | { 24 | v1.push_back(i); 25 | } 26 | printVector(v1); 27 | 28 | vector v2; 29 | for (int i = 9; i >= 0; i--) 30 | { 31 | v2.push_back(i); 32 | } 33 | printVector(v2); 34 | 35 | // 交换 36 | v1.swap(v2); 37 | printVector(v1); 38 | printVector(v2); 39 | } 40 | 41 | // 实际用途:巧用swap可以收缩内存空间 42 | void test02() 43 | { 44 | vector v; 45 | for (int i = 0; i < 100000; i++) 46 | { 47 | v.push_back(i); 48 | } 49 | 50 | cout << "v 容量为 " << v.capacity() << endl; 51 | cout << "v 大小为 " << v.size() << endl; 52 | 53 | v.resize(3); 54 | cout << "v 容量为 " << v.capacity() << endl; 55 | cout << "v 大小为 " << v.size() << endl; 56 | 57 | // 巧用swap收缩内存 58 | vector(v).swap(v); 59 | // vector(v) 匿名对象,拷贝构造 60 | cout << "v 容量为 " << v.capacity() << endl; 61 | cout << "v 大小为 " << v.size() << endl; 62 | } 63 | 64 | int main() 65 | { 66 | // test01(); 67 | test02(); 68 | return 0; 69 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/19_vector_预留空间.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // vector 预留空间 6 | 7 | // reserve(int len); // 容器预留len个元素长度,预留位置不初始化,元素不可访问 8 | 9 | void test01() 10 | { 11 | vector v; 12 | 13 | // 利用 reserve 预留空间 14 | v.reserve(100000); 15 | 16 | int num = 0; // 统计开辟次数 17 | int *p = NULL; 18 | 19 | for (int i = 0; i < 100000; i++) 20 | { 21 | v.push_back(i); 22 | 23 | if (p != &v[0]) 24 | { 25 | p = &v[0]; 26 | num++; 27 | } 28 | } 29 | 30 | cout << "开辟内存次数为 " << num << endl; 31 | } 32 | 33 | int main() 34 | { 35 | test01(); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/20_deque_构造函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // deque容器基本概念 6 | /* 7 | 功能: 8 | - 双端数组,可以对头端进行插入删除操作 9 | 10 | deque与vector区别: 11 | - vector 对头部的插入删除效率低,数据量越大,效率越低 12 | - deque对头部的插入删除速度快于vector 13 | - vector访问元素时速度更快 14 | 15 | deque内部工作原理: 16 | 内部有中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据 17 | 中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间 18 | 19 | deque容器的迭代器支持随机访问 20 | */ 21 | 22 | // deque构造函数 23 | /* 24 | - deque deqT; // 默认构造形式 25 | - deque(beg, end); // 构造函数将 [beg, end) 区间中的元素拷贝给本身 26 | - deque(n, elem); // 构造函数将 n 个 elem 拷贝给本身 27 | - deque(const deque &deq); // 拷贝构造函数 28 | */ 29 | 30 | void printDeque(const deque &d) 31 | { 32 | for (deque::const_iterator it = d.begin(); it != d.end(); it++) 33 | { 34 | // *it = 100; // 加 const 防止对传入的数据误修改 35 | cout << *it << " "; 36 | } 37 | cout << endl; 38 | } 39 | 40 | void test01() 41 | { 42 | deque d1; 43 | for (int i = 0; i < 10; i++) 44 | { 45 | d1.push_back(i); 46 | } 47 | printDeque(d1); 48 | 49 | deque d2(d1.begin(), d1.end()); 50 | printDeque(d2); 51 | 52 | deque d3(10, 100); 53 | printDeque(d3); 54 | 55 | deque d4(d3); 56 | printDeque(d4); 57 | } 58 | 59 | int main() 60 | { 61 | test01(); 62 | return 0; 63 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/21_deque_赋值操作.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // deque 赋值操作 6 | /* 7 | - deque& operator= (const deque &deq); // 重载等号操作符 8 | - assign(beg, end); // 将[beg, end)区间中的数据拷贝赋值给本身 9 | - assign(n, elem); // 将 n 个 elem 拷贝赋值给本身 10 | */ 11 | 12 | void printDeque(const deque &d) 13 | { 14 | for (deque::const_iterator it = d.begin(); it != d.end(); it++) 15 | { 16 | // *it = 100; // 加 const 防止对传入的数据误修改 17 | cout << *it << " "; 18 | } 19 | cout << endl; 20 | } 21 | 22 | void test01() 23 | { 24 | deque d1; 25 | for (int i = 0; i < 10; i++) 26 | { 27 | d1.push_back(i); 28 | } 29 | printDeque(d1); 30 | 31 | // operator= 赋值 32 | deque d2; 33 | d2 = d1; 34 | printDeque(d2); 35 | 36 | // assign 赋值 37 | deque d3; 38 | d3.assign(d1.begin(), d1.end()); 39 | printDeque(d3); 40 | 41 | deque d4; 42 | d4.assign(10, 100); 43 | printDeque(d4); 44 | } 45 | 46 | int main() 47 | { 48 | test01(); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/22_deque_大小操作.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // deque 大小操作 6 | /* 7 | - deque.empty(); // 判断容器是否为空 8 | - deque.size(); // 返回容器中元素的个数 9 | - deque.resize(num); // 重新指定容器的长度为num;若容器变长则以默认值填充新位置;若容器变短则删除末尾超出长度的元素 10 | - deque.resize(num, elem); // 同上,变长时使用elem填充新位置 11 | */ 12 | 13 | void printDeque(const deque &d) 14 | { 15 | for (deque::const_iterator it = d.begin(); it != d.end(); it++) 16 | { 17 | // *it = 100; // 加 const 防止对传入的数据误修改 18 | cout << *it << " "; 19 | } 20 | cout << endl; 21 | } 22 | 23 | void test01() 24 | { 25 | deque d1; 26 | for (int i = 0; i < 10; i++) 27 | { 28 | d1.push_back(i); 29 | } 30 | printDeque(d1); 31 | 32 | if (d1.empty()) 33 | { 34 | cout << "d1 为空" << endl; 35 | } 36 | else 37 | { 38 | cout << "d1 不为空" << endl; 39 | cout << "d1 的大小为 " << d1.size() << endl; 40 | // deque 没有容量概念 41 | } 42 | 43 | // d1.resize(15); 44 | d1.resize(15, 1); 45 | printDeque(d1); 46 | 47 | d1.resize(5); 48 | printDeque(d1); 49 | } 50 | 51 | int main() 52 | { 53 | test01(); 54 | return 0; 55 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/23_deque_插入与删除.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // deque 插入与删除 6 | 7 | /* 8 | 两端插入操作: 9 | - push_back(elem); // 在容器尾部添加一个数据 10 | - push_front(elem); // 在容器头部插入一个数据 11 | - pop_back(); // 删除容器最后一个数据 12 | - pop_front(); // 删除容器第一个数据 13 | 14 | 指定位置操作 15 | - insert(pos, elem); // 在pos位置插入一个elem元素的拷贝,返回新数据的位置 16 | - insert(pos, n, elem); // 在pos位置插入n个elem数据,无返回值 17 | - insert(pos, beg, end); // 在pos位置插入[beg, end)区间的数据,无返回值 18 | - clear(); // 清空容器的所有数据 19 | - erase(beg, end); // 删除[beg, end) 区间的数据,返回下一个数据的位置 20 | - erase(pos); // 删除pos位置的数据,返回下一个数据的位置 21 | */ 22 | 23 | void printDeque(const deque &d) 24 | { 25 | for (deque::const_iterator it = d.begin(); it != d.end(); it++) 26 | { 27 | // *it = 100; // 加 const 防止对传入的数据误修改 28 | cout << *it << " "; 29 | } 30 | cout << endl; 31 | } 32 | 33 | void test01() 34 | { 35 | deque d1; 36 | 37 | // 尾插 38 | d1.push_back(10); 39 | d1.push_back(20); 40 | 41 | // 头插 42 | d1.push_front(100); 43 | d1.push_front(200); 44 | 45 | // 200 100 10 20 46 | printDeque(d1); 47 | 48 | // 尾删 49 | d1.pop_back(); 50 | // 200 100 10 51 | printDeque(d1); 52 | 53 | // 头删 54 | d1.pop_front(); 55 | printDeque(d1); 56 | } 57 | 58 | void test02() 59 | { 60 | deque d1; 61 | d1.push_back(10); 62 | d1.push_back(20); 63 | d1.push_front(100); 64 | d1.push_front(200); 65 | printDeque(d1); // 200 100 10 20 66 | 67 | // insert 插入 68 | d1.insert(d1.begin(), 1000); 69 | d1.insert(d1.begin(), 2, 2000); 70 | printDeque(d1); 71 | // 按区间插入 72 | deque d2; 73 | d2.push_back(1); 74 | d2.push_back(2); 75 | d2.push_back(3); 76 | 77 | d1.insert(d1.begin(), d2.begin(), d2.end()); 78 | printDeque(d1); 79 | } 80 | 81 | void test03() 82 | { 83 | deque d1; 84 | d1.push_back(10); 85 | d1.push_back(20); 86 | d1.push_front(100); 87 | d1.push_front(200); 88 | printDeque(d1); // 200 100 10 20 89 | 90 | // 删除 91 | deque::iterator it = d1.begin(); 92 | it++; 93 | d1.erase(it); // 200 10 20 94 | printDeque(d1); 95 | // 按区间方式删除 96 | d1.erase(d1.begin(), d1.end()); // 等效于clear 97 | d1.clear(); // 清空 98 | printDeque(d1); 99 | } 100 | 101 | int main() 102 | { 103 | // test01(); 104 | // test02(); 105 | test03(); 106 | return 0; 107 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/24_deque_数据存取.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // deque 数据存取 6 | 7 | /* 8 | - at(int idx); // 返回索引idx所指的数据 9 | - operator[]; // 返回索引idx所指的数据 10 | - front(); // 返回容器中第一个数据元素 11 | - back(); // 返回容器中最后一个数据元素 12 | */ 13 | 14 | void test01() 15 | { 16 | deque d; 17 | d.push_back(20); 18 | d.push_back(30); 19 | d.push_back(40); 20 | d.push_front(10); 21 | 22 | // 通过[]方式访问元素 23 | for (int i = 0; i < d.size(); i++) 24 | { 25 | cout << d[i] << " "; 26 | } 27 | cout << endl; 28 | 29 | // 通过at访问元素 30 | for (int i = 0; i < d.size(); i++) 31 | { 32 | cout << d.at(i) << " "; 33 | } 34 | cout << endl; 35 | 36 | cout << "第一个元素为 " << d.front() << endl; 37 | cout << "最后一个元素为 " << d.back() << endl; 38 | } 39 | 40 | int main() 41 | { 42 | test01(); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/25_deque_排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // deque 排序 7 | 8 | // sort(iterator beg, tierator end) // 对beg和end区间内元素进行排序 9 | 10 | void printDeque(const deque &d) 11 | { 12 | for (deque::const_iterator it = d.begin(); it != d.end(); it++) 13 | { 14 | // *it = 100; // 加 const 防止对传入的数据误修改 15 | cout << *it << " "; 16 | } 17 | cout << endl; 18 | } 19 | 20 | void test01() 21 | { 22 | deque d; 23 | d.push_back(20); 24 | d.push_back(40); 25 | d.push_back(30); 26 | d.push_front(10); 27 | d.push_front(100); 28 | d.push_front(50); 29 | 30 | // 50 100 10 20 40 30 31 | printDeque(d); 32 | 33 | // 排序 34 | sort(d.begin(), d.end()); // 默认升序 35 | // 10 20 30 40 50 100 36 | printDeque(d); 37 | } 38 | 39 | int main() 40 | { 41 | test01(); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/27_stack_基本概念与常用接口.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // stack 基本概念 6 | 7 | /* 8 | stack先进后出(First In Last Out, FILO)的数据结构,只有一个出/入口 9 | 栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为 10 | 栈中进入数据 - 入栈 push 11 | 栈中弹出数据 - 出栈 pop 12 | */ 13 | 14 | // stack 常用接口 15 | /* 16 | 17 | 构造函数 18 | - stack stk; //stack采用模板类实现,stack对象的默认构造形式 19 | - stack(const stack &stk); // 拷贝构造函数 20 | 21 | 赋值操作 22 | - stack& operator= (const stack &stk); // 重载等号操作符 23 | 24 | 数据存取 25 | - push(elem); // 向栈顶添加元素 26 | - pop(); // 从栈顶移除第一个元素 27 | - top(); // 返回栈顶元素 28 | 29 | 大小操作 30 | - empty(); // 判断堆栈是否为空 31 | - size(); // 返回栈的大小 32 | 33 | */ 34 | 35 | void test01() 36 | { 37 | stack s; 38 | 39 | // 入栈 40 | s.push(10); 41 | s.push(20); 42 | s.push(30); 43 | s.push(40); 44 | 45 | cout << "栈的大小为 " << s.size() << endl; 46 | 47 | // 只要栈不为空,查看栈顶,并执行出栈操作 48 | while (!s.empty()) 49 | { 50 | // 查看栈顶元素 51 | cout << "栈顶元素为: " << s.top() << endl; 52 | 53 | // 出栈 54 | s.pop(); 55 | } 56 | 57 | cout << "栈的大小为 " << s.size() << endl; 58 | } 59 | 60 | int main() 61 | { 62 | test01(); 63 | return 0; 64 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/28_queue_基本概念与常用接口.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // queue 基本概念 6 | /* 7 | 先进先出(First In First Out, FIFO)的数据结构,一个入口一个出口 8 | 9 | 允许从一端新增元素,从另一端移除元素 10 | 队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为 11 | 进数据 --- 入队 push 12 | 出数据 --- 出队 pop 13 | */ 14 | 15 | // queue 常用接口 16 | /* 17 | 18 | 构造函数 19 | - queue que; // queue采用模板类实现,queue对象的默认构造形式 20 | - queue(const queue &que); // 拷贝构造函数 21 | 22 | 赋值操作 23 | - queue& operator= (const queue &que); // 重载等号运算符 24 | 25 | 数据存取 26 | - push(elem); // 往队尾添加元素 27 | - pop(); // 从队头移除第一个元素 28 | - back(); // 返回最后一个元素 29 | - front(); // 返回第一个元素 30 | 31 | 大小操作 32 | - empty(); // 判断堆栈是否为空 33 | - size(); // 返回栈的大小 34 | 35 | */ 36 | 37 | class Person 38 | { 39 | public: 40 | Person(string name, int age) 41 | { 42 | this->m_Name = name; 43 | this->m_Age = age; 44 | } 45 | string m_Name; 46 | int m_Age; 47 | }; 48 | 49 | void test01() 50 | { 51 | // 创建队列 52 | queue q; 53 | 54 | // 准备数据 55 | Person p1("张三", 30); 56 | Person p2("李四", 32); 57 | Person p3("王五", 29); 58 | Person p4("赵六", 28); 59 | 60 | // 入队 61 | q.push(p1); 62 | q.push(p2); 63 | q.push(p3); 64 | q.push(p4); 65 | 66 | cout << "队列大小为 " << q.size() << endl; 67 | 68 | // 队列不为空,则查看队头队尾,然后出队 69 | while (!q.empty()) 70 | { 71 | cout << "队头元素:" << q.front().m_Name << " " << q.front().m_Age << endl; 72 | cout << "队尾元素:" << q.back().m_Name << " " << q.back().m_Age << endl; 73 | // 出队 74 | q.pop(); 75 | cout << endl; 76 | } 77 | cout << "队列大小为 " << q.size() << endl; 78 | } 79 | 80 | int main() 81 | { 82 | test01(); 83 | return 0; 84 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/29_list_基本概念与构造函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // list容器基本概念 6 | /* 7 | 8 | 功能:将数据进行链式存储 9 | 链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的 10 | 11 | 链表的组成:链表由一系列结点组成 12 | 结点的组成:存储数据元素的数据域、存储下一个结点地址的指针域 13 | 14 | STL 中的链表是一个双向循环链表 15 | 16 | 由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器 17 | 18 | list的优点: 19 | - 采用动态存储分配,不会造成内存浪费和溢出 20 | - 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素 21 | list的缺点: 22 | - 链表灵活,但空间(需要存储指针域)和时间(遍历)额外消耗较大 23 | 24 | list重要特性:插入操作和删除操作都不会造成原有list迭代器的失效,这与vector不同 25 | 26 | */ 27 | 28 | // list构造函数 29 | /* 30 | 31 | - list lst; // list采用模板类实现,对象的默认构造形式 32 | - list(beg, end); // 构造函数将 [beg, end) 区间中的元素拷贝给本身 33 | - list(n, elem); // 构造函数将n个elem拷贝给本身 34 | - list(const list &lst); // 拷贝构造函数 35 | 36 | */ 37 | 38 | void printList(const list &L) 39 | { 40 | for (list::const_iterator it = L.begin(); it != L.end(); it++) 41 | { 42 | cout << *it << " "; 43 | } 44 | cout << endl; 45 | } 46 | 47 | void test01() 48 | { 49 | // 创建容器 50 | list L1; // 默认构造 51 | 52 | // 添加数据 53 | L1.push_back(10); 54 | L1.push_back(20); 55 | L1.push_back(30); 56 | L1.push_back(40); 57 | 58 | // 遍历打印 59 | printList(L1); 60 | 61 | // 区间方式 62 | list L2(L1.begin(), L1.end()); 63 | printList(L2); 64 | 65 | // 拷贝构造 66 | list L3(L2); 67 | printList(L3); 68 | 69 | // n个elem 70 | list L4(10, 1000); 71 | printList(L4); 72 | } 73 | 74 | int main() 75 | { 76 | test01(); 77 | return 0; 78 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/30_list_赋值与交换.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // list赋值与交换 6 | /* 7 | 8 | - assign(beg, end); // 将[beg, end) 区间中的数据拷贝赋值给本身 9 | - assign(n, elem); // 将n个elem拷贝赋值给本身 10 | - list& operator= (const list &lst); // 重载等号操作符 11 | - swap(lst); // 将lst与本身的元素互换 12 | 13 | */ 14 | 15 | void printList(const list &L) 16 | { 17 | for (list::const_iterator it = L.begin(); it != L.end(); it++) 18 | { 19 | cout << *it << " "; 20 | } 21 | cout << endl; 22 | } 23 | 24 | void test01() 25 | { 26 | list L1; 27 | L1.push_back(10); 28 | L1.push_back(20); 29 | L1.push_back(30); 30 | L1.push_back(40); 31 | printList(L1); 32 | 33 | list L2; 34 | // operator= 方式赋值 35 | L2 = L1; 36 | 37 | // assign拷贝 38 | list L3; 39 | L3.assign(L2.begin(), L2.end()); 40 | printList(L3); 41 | 42 | list L4; 43 | L4.assign(10, 100); 44 | printList(L4); 45 | } 46 | 47 | void test02() 48 | { 49 | list L1; 50 | L1.push_back(10); 51 | L1.push_back(20); 52 | L1.push_back(30); 53 | L1.push_back(40); 54 | 55 | list L2; 56 | L2.assign(10, 100); 57 | 58 | cout << "交换前:" << endl; 59 | printList(L1); 60 | printList(L2); 61 | 62 | L1.swap(L2); 63 | cout << "交换后:" << endl; 64 | printList(L1); 65 | printList(L2); 66 | } 67 | 68 | int main() 69 | { 70 | // test01(); 71 | test02(); 72 | return 0; 73 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/31_list_大小操作.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // list 大小操作 6 | 7 | /* 8 | 9 | - size(); // 返回容器中元素的个数 10 | - empty(); // 判断容器是否为空 11 | - resize(num); // 重新指定容器的长度为num;若容器变长则以默认值填充新位置;若容器变短则删除末尾超出长度的元素 12 | - resize(num, elem); // 同上,变长时使用elem填充新位置 13 | 14 | */ 15 | 16 | void printList(const list &L) 17 | { 18 | for (list::const_iterator it = L.begin(); it != L.end(); it++) 19 | { 20 | cout << *it << " "; 21 | } 22 | cout << endl; 23 | } 24 | 25 | void test01() 26 | { 27 | list L1; 28 | L1.push_back(10); 29 | L1.push_back(20); 30 | L1.push_back(30); 31 | L1.push_back(40); 32 | 33 | printList(L1); 34 | 35 | if (L1.empty()) 36 | { 37 | cout << "L1 为空" << endl; 38 | } 39 | else 40 | { 41 | cout << "L1非空" << endl; 42 | cout << "L1 的元素个数为" << L1.size() << endl; 43 | } 44 | 45 | // 重新指定大小 46 | // L1.resize(10); 47 | L1.resize(10, 1); 48 | printList(L1); 49 | 50 | L1.resize(2); 51 | printList(L1); 52 | } 53 | 54 | int main() 55 | { 56 | test01(); 57 | return 0; 58 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/32_list_插入与删除.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // list 插入与删除 6 | 7 | /* 8 | 9 | - push_back(elem); // 在容器尾部加入一个元素 10 | - pop_back(); // 删除容器中最后一个元素 11 | - push_front(elem); // 在容器开头插入一个元素 12 | - pop_front(); // 从容器开头移除第一个元素 13 | - insert(pos, elem); // 在pos位置插elem元素的拷贝,返回新数据的位置 14 | - insert(pos, n, elem); // 在pos位置插入n个elem元素,无返回值 15 | - insert(pos, beg, end); // 在pos位置插入[beg, end)区间的数据,无返回值 16 | - clear(); // 移除容器的所有数据 17 | - erase(beg, end); // 删除[beg, end)区间的数据,返回下一个数据的位置 18 | - erase(pos); // 删除pos位置的数据,返回下一个数据的位置 19 | - remove(elem); // 删除容器中所有与elem值匹配的元素 20 | 21 | */ 22 | 23 | void printList(const list &L) 24 | { 25 | for (list::const_iterator it = L.begin(); it != L.end(); it++) 26 | { 27 | cout << *it << " "; 28 | } 29 | cout << endl; 30 | } 31 | 32 | void test01() 33 | { 34 | list L; 35 | 36 | // 尾插 37 | L.push_back(10); 38 | L.push_back(20); 39 | L.push_back(30); 40 | 41 | // 头插 42 | L.push_front(100); 43 | L.push_front(200); 44 | 45 | printList(L); 46 | 47 | // 尾删 48 | L.pop_back(); 49 | printList(L); 50 | 51 | // 头删 52 | L.pop_front(); 53 | printList(L); 54 | 55 | // 插入 56 | // L.insert(L.begin(), 1000); 57 | list::iterator it = L.begin(); 58 | L.insert(++it, 1000); 59 | printList(L); 60 | 61 | // 删除 62 | it = L.begin(); 63 | it++; 64 | L.erase(it); 65 | printList(L); 66 | 67 | // 移除 68 | L.push_back(10); 69 | L.push_back(10); 70 | printList(L); 71 | L.remove(10); // 无需传入迭代器,移除所有匹配项 72 | printList(L); 73 | 74 | // 清空 75 | L.clear(); 76 | cout << L.size() << endl; 77 | } 78 | 79 | int main() 80 | { 81 | test01(); 82 | return 0; 83 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/33_list_数据存取.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // list数据存取 6 | // front(); // 返回第一个元素 7 | // back(); // 返回最后一个元素 8 | 9 | void test01() 10 | { 11 | list L1; 12 | L1.push_back(10); 13 | L1.push_back(20); 14 | L1.push_back(30); 15 | L1.push_back(40); 16 | 17 | // L1[0]; 不可以用[]或at访问list容器中的元素 18 | // list本质是列表,不是用连续线性空间存储数据,迭代器也是不支持随机访问的 19 | 20 | cout << "L1.front() = " << L1.front() << endl; 21 | cout << "L1.back() = " << L1.back() << endl; 22 | 23 | // 验证迭代器是不支持随机访问的 24 | list::iterator it = L1.begin(); 25 | it++; // 可以 26 | // it += 1; // 报错 27 | // it = it + 1; // 报错 28 | it--; //支持双向 29 | } 30 | 31 | int main() 32 | { 33 | test01(); 34 | return 0; 35 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/34_list_反转与排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // list 反转与排序 6 | // reverse(); // 反转链表 7 | // sort(); // 链表排序 8 | 9 | void printList(const list &lst) 10 | { 11 | for (list::const_iterator it = lst.begin(); it != lst.end(); it++) 12 | { 13 | cout << *it << " "; 14 | } 15 | cout << endl; 16 | } 17 | 18 | bool myCompare(int v1, int v2) 19 | { 20 | // 降序 就让第一个数大于第二个数 21 | return v1 > v2; 22 | } 23 | 24 | void test01() 25 | { 26 | // 反转 27 | list L1; 28 | L1.push_back(20); 29 | L1.push_back(10); 30 | L1.push_back(50); 31 | L1.push_back(30); 32 | L1.push_back(40); 33 | cout << "反转前:" << endl; 34 | printList(L1); 35 | 36 | L1.reverse(); 37 | cout << "反转后:" << endl; 38 | printList(L1); 39 | 40 | // 排序 41 | L1.sort(); 42 | cout << "排序后:" << endl; 43 | printList(L1); 44 | // 所有不支持随机访问迭代器的容器不能用标准sort()算法 45 | // 降序排序 46 | L1.sort(myCompare); // 提供回调函数 47 | printList(L1); 48 | } 49 | 50 | int main() 51 | { 52 | test01(); 53 | return 0; 54 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/35_list_排序案例.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // list 排序案例 6 | // 案例描述:将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高 7 | // 排序规则:按照年龄进行升序,如果年龄相同则按身高进行降序 8 | 9 | class Person 10 | { 11 | public: 12 | Person(string name, int age, int height) 13 | { 14 | this->m_Name = name; 15 | this->m_Age = age; 16 | this->m_Height = height; 17 | } 18 | 19 | string m_Name; 20 | int m_Age; 21 | int m_Height; 22 | }; 23 | 24 | void printPersonList(const list &lst) 25 | { 26 | for (list::const_iterator it = lst.begin(); it != lst.end(); it++) 27 | { 28 | cout << "姓名:" << (*it).m_Name 29 | << " 年龄:" << it->m_Age 30 | << " 身高:" << it->m_Height 31 | << endl; 32 | } 33 | } 34 | 35 | // 指定排序顺序 36 | bool comparePerson(Person &p1, Person &p2) 37 | { 38 | // 按年龄升序 39 | if (p1.m_Age == p2.m_Age) 40 | { 41 | // 年龄相同,按身高降序 42 | return p1.m_Height > p2.m_Height; 43 | } 44 | return p1.m_Age < p2.m_Age; 45 | } 46 | 47 | void test01() 48 | { 49 | list L; 50 | 51 | Person p1("A", 35, 175); 52 | Person p2("B", 25, 178); 53 | Person p3("C", 40, 170); 54 | Person p4("D", 38, 180); 55 | Person p5("E", 35, 165); 56 | Person p6("F", 35, 170); 57 | 58 | L.push_back(p1); 59 | L.push_back(p2); 60 | L.push_back(p3); 61 | L.push_back(p4); 62 | L.push_back(p5); 63 | L.push_back(p6); 64 | 65 | printPersonList(L); 66 | 67 | cout << "------排序后------" << endl; 68 | 69 | L.sort(comparePerson); 70 | printPersonList(L); 71 | } 72 | 73 | int main() 74 | { 75 | test01(); 76 | return 0; 77 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/36_set_multiset_基本概念_构造与赋值.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // set基本概念 6 | /* 7 | 8 | 简介: 9 | 所有元素都会在插入时自动排序 10 | 本质: 11 | set/mutiset 属于关联式容器,底层结构是用二叉树实现 12 | 13 | set与 multiset 区别: 14 | - set 不允许容器中有重复的元素 15 | - multiset 允许容器中有重复的元素 16 | 17 | */ 18 | 19 | // set构造与赋值 20 | /* 21 | 22 | 构造: 23 | - set st; // 默认构造函数 24 | - set(const set &st); // 拷贝构造函数 25 | 26 | 赋值: 27 | - set& operator= (const set &st); // 重载等号操作符 28 | 29 | */ 30 | 31 | void printSet(const set &s) 32 | { 33 | for (set::const_iterator it = s.begin(); it != s.end(); it++) 34 | { 35 | cout << *it << " "; 36 | } 37 | cout << endl; 38 | } 39 | 40 | void test01() 41 | { 42 | set s1; 43 | // 插入数据只有 insert 方式 44 | s1.insert(10); 45 | s1.insert(20); 46 | s1.insert(10); 47 | s1.insert(10); 48 | s1.insert(40); 49 | s1.insert(30); 50 | 51 | // 遍历容器 52 | printSet(s1); 53 | // set容器特点:所有元素插入时自动排序,不允许插入重复值 54 | 55 | // 拷贝构造 56 | set s2(s1); 57 | printSet(s2); 58 | 59 | // 赋值 60 | set s3; 61 | s3 = s2; 62 | printSet(s3); 63 | } 64 | 65 | int main() 66 | { 67 | test01(); 68 | return 0; 69 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/37_set_大小与交换.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // set 大小与交换 6 | /* 7 | - size(); // 返回容器中元素的数目 8 | - empty(); // 判断容器是否为空 9 | - swap(st); // 交换两个集合容器 10 | */ 11 | 12 | void printSet(const set &s) 13 | { 14 | for (set::const_iterator it = s.begin(); it != s.end(); it++) 15 | { 16 | cout << *it << " "; 17 | } 18 | cout << endl; 19 | } 20 | 21 | // 大小 22 | void test01() 23 | { 24 | set s1; 25 | s1.insert(10); 26 | s1.insert(20); 27 | s1.insert(30); 28 | s1.insert(40); 29 | 30 | // 判断是否为空 31 | if (s1.empty()) 32 | { 33 | cout << "s1 为空" << endl; 34 | } 35 | else 36 | { 37 | cout << "s1 不为空" << endl; 38 | cout << "s1 大小为 " << s1.size() << endl; 39 | } 40 | } 41 | 42 | // 交换 43 | void test02() 44 | { 45 | set s1; 46 | s1.insert(10); 47 | s1.insert(20); 48 | s1.insert(30); 49 | s1.insert(40); 50 | 51 | set s2; 52 | s2.insert(100); 53 | s2.insert(200); 54 | s2.insert(300); 55 | s2.insert(400); 56 | 57 | cout << "交换前:" << endl; 58 | printSet(s1); 59 | printSet(s2); 60 | 61 | s1.swap(s2); 62 | cout << "交换后:" << endl; 63 | printSet(s1); 64 | printSet(s2); 65 | } 66 | 67 | int main() 68 | { 69 | test01(); 70 | test02(); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/38_set_插入与删除.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // set 插入与删除 6 | 7 | /* 8 | 9 | - insert(elem); // 在容器中插入元素 10 | - clear(); // 清除所有元素 11 | - erase(pos); // 删除pos迭代器所指的元素,返回下一个元素的迭代器 12 | - erase(beg, end); // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器 13 | - erase(elem); // 删除容器中值为elem的元素 14 | 15 | */ 16 | 17 | void printSet(const set &s) 18 | { 19 | for (set::const_iterator it = s.begin(); it != s.end(); it++) 20 | { 21 | cout << *it << " "; 22 | } 23 | cout << endl; 24 | } 25 | 26 | void test01() 27 | { 28 | set s1; 29 | 30 | // 插入 31 | s1.insert(40); 32 | s1.insert(10); 33 | s1.insert(30); 34 | s1.insert(20); 35 | printSet(s1); 36 | 37 | // 删除 38 | s1.erase(s1.begin()); 39 | printSet(s1); 40 | s1.erase(30); 41 | printSet(s1); 42 | 43 | // 清空 44 | // s1.erase(s1.begin(), s1.end()); 45 | s1.clear(); 46 | printSet(s1); 47 | } 48 | 49 | int main() 50 | { 51 | test01(); 52 | return 0; 53 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/39_set_查找与统计.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // set 查找与统计 6 | // find(key); // 查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end() 7 | // count(key); // 统计key的元素个数 8 | 9 | void test01() 10 | { 11 | set s1; 12 | s1.insert(40); 13 | s1.insert(20); 14 | s1.insert(10); 15 | s1.insert(30); 16 | 17 | set::iterator pos = s1.find(30); 18 | 19 | if (pos != s1.end()) 20 | { 21 | cout << "找到元素:" << *pos << endl; 22 | } 23 | else 24 | { 25 | cout << "未找到元素" << endl; 26 | } 27 | } 28 | 29 | void test02() 30 | { 31 | set s1; 32 | s1.insert(40); 33 | s1.insert(20); 34 | s1.insert(10); 35 | s1.insert(30); 36 | s1.insert(30); 37 | s1.insert(30); 38 | 39 | // 统计30的个数 40 | int num = s1.count(30); 41 | // 对于set,统计结果只可能为0或1 42 | cout << "num = " << num << endl; 43 | num = s1.count(300); 44 | cout << "num = " << num << endl; 45 | } 46 | 47 | int main() 48 | { 49 | test01(); 50 | test02(); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/40_set与multiset区别.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // set 与 multiset 区别 6 | /* 7 | - set 不可以插入重复数据,multiset 可以 8 | - set 插入数据的同时会返回插入结果,表示是否插入成功 9 | - multiset 不会检测数据,因此可以插入重复数据 10 | */ 11 | 12 | void showResult(const pair::iterator, bool> &ret) 13 | { 14 | if (ret.second) 15 | { 16 | cout << "插入成功" << endl; 17 | } 18 | else 19 | { 20 | cout << "插入失败" << endl; 21 | } 22 | } 23 | 24 | void test01() 25 | { 26 | set s; 27 | pair::iterator, bool> ret = s.insert(10); 28 | showResult(ret); 29 | showResult(s.insert(10)); 30 | } 31 | 32 | void test02() 33 | { 34 | multiset ms; 35 | ms.insert(10); // 返回插入位置的迭代器 36 | ms.insert(10); 37 | 38 | for (multiset::iterator it = ms.begin(); it != ms.end(); it++) 39 | { 40 | cout << *it << " "; 41 | } 42 | cout << endl; 43 | } 44 | 45 | int main() 46 | { 47 | test01(); 48 | test02(); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/41_pair_对组创建.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // pair 对组创建 5 | // pair p (value1, value2); 6 | // pair p = make_pair(value1, value2); 7 | 8 | void test01() 9 | { 10 | // 第一种方式创建 11 | pair p("Tom", 20); 12 | cout << "姓名:" << p.first << " 年龄:" << p.second << endl; 13 | 14 | // 第二种方式 15 | pair p2 = make_pair("Jerry", 18); 16 | cout << "姓名:" << p2.first << " 年龄:" << p2.second << endl; 17 | } 18 | 19 | int main() 20 | { 21 | test01(); 22 | return 0; 23 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/42_set_内置类型指定规则排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // set排序 6 | // 利用仿函数,可以改变排序规则 7 | 8 | class MyCompare 9 | { 10 | public: 11 | bool operator()(int v1, int v2) const 12 | { 13 | return v1 > v2; 14 | } 15 | }; 16 | 17 | void printSet(const set &s) 18 | { 19 | for (set::const_iterator it = s.begin(); it != s.end(); it++) 20 | { 21 | cout << *it << " "; 22 | } 23 | cout << endl; 24 | } 25 | 26 | void test01() 27 | { 28 | set s1; 29 | s1.insert(20); 30 | s1.insert(40); 31 | s1.insert(10); 32 | s1.insert(50); 33 | s1.insert(30); 34 | printSet(s1); 35 | 36 | // 指定排序规则为降序 37 | set s2; // 在创建时指定排序规则 38 | s2.insert(20); // 插入时已经无法更改排序规则 39 | s2.insert(40); 40 | s2.insert(10); 41 | s2.insert(50); 42 | s2.insert(30); 43 | 44 | for (set::iterator it = s2.begin(); it != s2.end(); it++) 45 | { 46 | cout << *it << " "; 47 | } 48 | cout << endl; 49 | } 50 | 51 | int main() 52 | { 53 | test01(); 54 | return 0; 55 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/43_set_自定义数据类型排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // set 自定义数据类型排序 6 | 7 | class Person 8 | { 9 | public: 10 | Person(string name, int age) 11 | { 12 | this->m_Name = name; 13 | this->m_Age = age; 14 | } 15 | 16 | string m_Name; 17 | int m_Age; 18 | }; 19 | 20 | class comparePerson 21 | { 22 | public: 23 | bool operator()(const Person &p1, const Person p2) const 24 | { 25 | return p1.m_Age > p2.m_Age; 26 | } 27 | }; 28 | 29 | void test01() 30 | { 31 | // 自定义数据类型都按指定规则排序 32 | set s; 33 | 34 | // 创建Person对象 35 | Person p1("A", 24); 36 | Person p2("B", 28); 37 | Person p3("C", 25); 38 | Person p4("D", 21); 39 | 40 | s.insert(p1); 41 | s.insert(p2); 42 | s.insert(p3); 43 | s.insert(p4); 44 | 45 | for (set::iterator it = s.begin(); it != s.end(); it++) 46 | { 47 | cout << "姓名:" << it->m_Name 48 | << " 年龄:" << it->m_Age 49 | << endl; 50 | } 51 | } 52 | 53 | int main() 54 | { 55 | test01(); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/44_map_multimap_基本概念_构造与赋值.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // map/multimap 容器简介 6 | /* 7 | 8 | 简介: 9 | - map 中所有元素都是 pair 10 | - pair 中第一个元素为 key(键值),起到索引作用;第二个元素为 value(实值) 11 | - 所有元素都会根据元素的键值自动排序 12 | 13 | 本质: 14 | map/multimap 属于关联式容器,底层结构用二叉树实现 15 | 16 | 优点: 17 | 可以根据 key 快读找到 value 值 18 | 19 | map 和 multimap 区别: 20 | - map 不允许容器中有重复 key 值元素 21 | - multimap 允许容器中有重复 key 值元素 22 | 23 | */ 24 | 25 | // map 构造与赋值 26 | /* 27 | 28 | 构造: 29 | - map mp; // map 默认构造函数 30 | - map(const map &mp); // 拷贝构造函数 31 | 32 | 赋值: 33 | - map& operator= (const map &mp); // 重载等号操作符 34 | 35 | */ 36 | 37 | void printMap(const map &m) 38 | { 39 | for (map::const_iterator it = m.begin(); it != m.end(); it++) 40 | { 41 | cout << "Key = " << (*it).first << " Value = " << it->second << endl; 42 | } 43 | cout << endl; 44 | } 45 | 46 | void test01() 47 | { 48 | // 创建map容器 49 | map m; 50 | 51 | m.insert(pair(2, 20)); 52 | m.insert(pair(4, 40)); 53 | m.insert(pair(3, 30)); 54 | m.insert(pair(1, 10)); 55 | 56 | printMap(m); 57 | 58 | // 拷贝构造 59 | map m2(m); 60 | printMap(m2); 61 | 62 | // 赋值 63 | map m3; 64 | m3 = m2; 65 | printMap(m3); 66 | } 67 | 68 | int main() 69 | { 70 | test01(); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/45_map_大小与交换.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // map 大小与交换 6 | /* 7 | 8 | - size(); // 返回容器中元素的数目 9 | - empty(); // 判断容器是否为空 10 | - swap(st); // 交换两个容器 11 | 12 | */ 13 | 14 | void printMap(const map &m) 15 | { 16 | for (map::const_iterator it = m.begin(); it != m.end(); it++) 17 | { 18 | cout << "Key = " << (*it).first << " Value = " << it->second << endl; 19 | } 20 | cout << endl; 21 | } 22 | 23 | // 大小 24 | void test01() 25 | { 26 | map m; 27 | m.insert(pair(2, 20)); 28 | m.insert(pair(4, 40)); 29 | m.insert(pair(3, 30)); 30 | m.insert(pair(1, 10)); 31 | 32 | if (m.empty()) 33 | { 34 | cout << "m为空" << endl; 35 | } 36 | else 37 | { 38 | cout << "m非空" << endl; 39 | cout << "m的大小为 " << m.size() << endl; 40 | } 41 | } 42 | 43 | // 交换 44 | void test02() 45 | { 46 | map m1; 47 | m1.insert(pair(2, 20)); 48 | m1.insert(pair(3, 30)); 49 | m1.insert(pair(1, 10)); 50 | 51 | map m2; 52 | m2.insert(pair(2, 200)); 53 | m2.insert(pair(4, 400)); 54 | m2.insert(pair(3, 300)); 55 | m2.insert(pair(1, 100)); 56 | 57 | cout << "交换前:" << endl; 58 | printMap(m1); 59 | printMap(m2); 60 | 61 | m1.swap(m2); 62 | cout << "交换后:" << endl; 63 | printMap(m1); 64 | printMap(m2); 65 | } 66 | 67 | int main() 68 | { 69 | // test01(); 70 | test02(); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/46_map_插入与删除.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // map 插入与删除 6 | /* 7 | 8 | - insert(elem); // 在容器中插入元素 9 | - clear(); // 清除所有元素 10 | - erase(); // 删除pos迭代器所指的元素,返回下一个元素的迭代器 11 | - erase(beg, end) // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器 12 | - erase(key); // 删除容器中值为key的元素 13 | 14 | */ 15 | 16 | void printMap(const map &m) 17 | { 18 | for (map::const_iterator it = m.begin(); it != m.end(); it++) 19 | { 20 | cout << "Key = " << (*it).first << " Value = " << it->second << endl; 21 | } 22 | cout << endl; 23 | } 24 | 25 | void test01() 26 | { 27 | map m; 28 | 29 | // 插入 30 | // 第一种 31 | m.insert(pair(1, 10)); 32 | 33 | // 第二种 34 | m.insert(make_pair(2, 20)); 35 | 36 | // 第三种 37 | m.insert(map::value_type(3, 30)); 38 | 39 | // 第四种 40 | m[4] = 40; // 不建议 41 | cout << m[5] << endl; // 会创建Key为5,Value为默认值0的元素 42 | cout << m[4] << endl; // 可以返回 Key = 4 对应的 Value 43 | 44 | printMap(m); 45 | 46 | // 删除 47 | m.erase(m.begin()); 48 | printMap(m); 49 | 50 | m.erase(3); // 按照Key删除 51 | printMap(m); 52 | 53 | // 清空 54 | // m.erase(m.begin(), m.end()); 55 | m.clear(); 56 | } 57 | 58 | int main() 59 | { 60 | test01(); 61 | return 0; 62 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/47_map_查找与统计.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // map 查找与统计 6 | // find(key); // 查找key是否存在,存在则返回该键的元素的迭代器;若不存在,则返回set.end() 7 | // count(key); // 统计key的元素个数,对于map,结果为0或1;multimap的结果可以大于1 8 | 9 | void test01() 10 | { 11 | // 查找 12 | map m; 13 | m.insert(make_pair(1, 10)); 14 | m.insert(make_pair(2, 20)); 15 | m.insert(make_pair(3, 30)); 16 | m.insert(make_pair(3, 40)); // map不允许插入key相同的元素,插入失败 17 | 18 | map::iterator pos = m.find(3); 19 | // map::iterator pos = m.find(4); 20 | 21 | if (pos != m.end()) 22 | { 23 | cout << "查到了元素:" << (*pos).first << ": " << (*pos).second << endl; 24 | } 25 | else 26 | { 27 | cout << "未找到元素" << endl; 28 | } 29 | 30 | // 统计 31 | int num = m.count(3); 32 | cout << "num = " << num << endl; 33 | } 34 | 35 | int main() 36 | { 37 | test01(); 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/48_map_排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // map 排序 6 | 7 | // 利用仿函数修改排序规则 8 | class MyCompare 9 | { 10 | public: 11 | bool operator()(int v1, int v2) const 12 | { 13 | return v1 > v2; 14 | } 15 | }; 16 | 17 | void test01() 18 | { 19 | map m; 20 | m.insert(make_pair(1, 10)); 21 | m.insert(make_pair(2, 20)); 22 | m.insert(make_pair(3, 30)); 23 | m.insert(make_pair(4, 40)); 24 | m.insert(make_pair(5, 50)); 25 | 26 | for (map::const_iterator it = m.begin(); it != m.end(); it++) 27 | { 28 | cout << "Key = " << (*it).first << " Value = " << it->second << endl; 29 | } 30 | cout << endl; 31 | } 32 | 33 | int main() 34 | { 35 | test01(); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /Chapter_04_STL_容器/49_案例_员工分组.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // STL容器 案例:员工分组 7 | /* 8 | 案例描述: 9 | - 10名新员工(ABCDEFGHIJ),需要指派在哪个部门工作 10 | - 员工信息:姓名、工资 11 | - 部门:策划、美术、研发 12 | - 随机给10名员工分配部门和工资 13 | - 通过multimap进行信息的插入:key--部门编号, value--员工 14 | - 分部门显示员工信息 15 | */ 16 | 17 | #define CEHUA 0 18 | #define MEISHU 1 19 | #define YANFA 2 20 | 21 | class Worker 22 | { 23 | public: 24 | string m_Name; 25 | int m_Salary; 26 | }; 27 | 28 | void creatWorker(vector &v) 29 | { 30 | string nameSeed = "ABCDEFGHIJ"; 31 | for (int i = 0; i < 10; i++) 32 | { 33 | Worker worker; 34 | worker.m_Name = "员工"; 35 | worker.m_Name += nameSeed[i]; 36 | 37 | worker.m_Salary = rand() % 10000 + 10000; // 10000 ~ 19999 38 | v.push_back(worker); 39 | } 40 | } 41 | 42 | void setGroup(vector &v, multimap &m) 43 | { 44 | for (vector::iterator it = v.begin(); it != v.end(); it++) 45 | { 46 | // 产生随机部门编号 47 | int deptId = rand() % 3; 48 | 49 | // 将员工插入到分组中 50 | // key部门编号, value员工 51 | m.insert(make_pair(deptId, *it)); 52 | } 53 | } 54 | 55 | void printWorker(multimap &m, int deptId) 56 | { 57 | multimap::iterator pos = m.find(deptId); 58 | int count = m.count(deptId); // 统计具体人数 59 | int index = 0; 60 | for (; pos != m.end() && index < count; pos++, index++) 61 | { 62 | cout << "姓名:" << pos->second.m_Name << "\t" << pos->second.m_Salary << endl; 63 | } 64 | cout << endl; 65 | } 66 | 67 | void showWorkerByGroup(multimap &m) 68 | { 69 | cout << "策划部门:" << endl; 70 | printWorker(m, CEHUA); 71 | cout << "美术部门" << endl; 72 | printWorker(m, MEISHU); 73 | cout << "研发部门" << endl; 74 | printWorker(m, YANFA); 75 | } 76 | 77 | int main() 78 | { 79 | srand((unsigned int)time(NULL)); 80 | 81 | // 1、创建员工 82 | vector vWorkers; 83 | creatWorker(vWorkers); 84 | 85 | // 测试 86 | // for (vector::iterator it = vWorkers.begin(); it != vWorkers.end(); it++) 87 | // { 88 | // cout << it->m_Name << "\t" << it->m_Salary << endl; 89 | // } 90 | 91 | // 2、员工分组 92 | multimap mWorkers; 93 | setGroup(vWorkers, mWorkers); 94 | 95 | // 3、分组显示员工 96 | showWorkerByGroup(mWorkers); 97 | 98 | return 0; 99 | } -------------------------------------------------------------------------------- /Chapter_05_STL_函数对象/01_函数对象_基本使用.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 函数对象概念 5 | /* 6 | 概念: 7 | - 重载函数调用操作符的类,其对象成为函数对象 8 | - 函数对象使用重载的()时,行为类似函数调用,故也叫仿函数 9 | 10 | 本质: 11 | 函数对象(仿函数)是一个类,不是一个函数 12 | */ 13 | 14 | // 函数对象的使用 15 | /* 16 | - 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值 17 | - 函数对象超出普通函数的概念,函数对象可以有自己的状态 18 | - 函数对象可以作为参数传递 19 | */ 20 | 21 | class MyAdd 22 | { 23 | public: 24 | int operator()(int v1, int v2) 25 | { 26 | return v1 + v2; 27 | } 28 | }; 29 | 30 | // 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值 31 | void test01() 32 | { 33 | MyAdd myAdd; 34 | cout << myAdd(10, 10) << endl; 35 | } 36 | 37 | // 函数对象超出普通函数的概念,函数对象可以有自己的状态 38 | class MyPrint 39 | { 40 | public: 41 | MyPrint() 42 | { 43 | this->count = 0; 44 | } 45 | void operator()(string test) 46 | { 47 | cout << test << endl; 48 | this->count++; 49 | } 50 | 51 | int count; // 内部自己状态 52 | }; 53 | 54 | void test02() 55 | { 56 | MyPrint myPrint; 57 | myPrint("Hello world."); 58 | myPrint("Hello world."); 59 | myPrint("Hello world."); 60 | cout << "myPrint调用次数为: " << myPrint.count << endl; 61 | } 62 | 63 | // 函数对象可以作为参数传递 64 | void doPrint(MyPrint &mp, string test) 65 | { 66 | mp(test); 67 | } 68 | 69 | void test03() 70 | { 71 | MyPrint myPrint; 72 | doPrint(myPrint, "Hello C++."); 73 | } 74 | 75 | int main() 76 | { 77 | // test01(); 78 | // test02(); 79 | test03(); 80 | return 0; 81 | } -------------------------------------------------------------------------------- /Chapter_05_STL_函数对象/02_谓词_一元谓词.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // 谓词概念 7 | /* 8 | - 返回bool类型的仿函数称为谓词 9 | - 如果operator() 接受一个参数,那么称为一元谓词 10 | - 如果operator() 接受两个参数,那么称为二元谓词 11 | */ 12 | 13 | class GreaterFive 14 | { 15 | public: 16 | // 一元谓词 17 | bool operator()(int val) 18 | { 19 | return val > 5; 20 | } 21 | }; 22 | 23 | void test01() 24 | { 25 | vector v; 26 | for (int i = 0; i < 10; i++) 27 | { 28 | v.push_back(i); 29 | } 30 | 31 | // 查找容器中有无大于5的数字 32 | // GreaterFive() 创建匿名函数对象 33 | vector::iterator it = find_if(v.begin(), v.end(), GreaterFive()); 34 | if (it == v.end()) 35 | { 36 | cout << "未找到" << endl; 37 | } 38 | else 39 | { 40 | cout << "找到了大于5的数字, 为: " << *it << endl; 41 | } 42 | } 43 | 44 | int main() 45 | { 46 | test01(); 47 | return 0; 48 | } -------------------------------------------------------------------------------- /Chapter_05_STL_函数对象/03_谓词_二元谓词.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // 二元谓词 7 | 8 | void printVector(vector &v) 9 | { 10 | for (vector::iterator it = v.begin(); it != v.end(); it++) 11 | { 12 | cout << *it << " "; 13 | } 14 | cout << endl; 15 | } 16 | 17 | class MyCompare 18 | { 19 | public: 20 | bool operator()(int val1, int val2) 21 | { 22 | return val1 > val2; 23 | } 24 | }; 25 | 26 | void test01() 27 | { 28 | vector v; 29 | v.push_back(40); 30 | v.push_back(20); 31 | v.push_back(30); 32 | v.push_back(50); 33 | v.push_back(10); 34 | 35 | sort(v.begin(), v.end()); 36 | printVector(v); 37 | 38 | // 使用函数对象,改变排序规则为降序 39 | sort(v.begin(), v.end(), MyCompare()); 40 | printVector(v); 41 | } 42 | 43 | int main() 44 | { 45 | test01(); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /Chapter_05_STL_函数对象/04_内建函数对象_算数仿函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 内建函数对象 6 | /* 7 | 概念: 8 | STL内建的一些函数对象 9 | 10 | 分类: 11 | - 算数仿函数 12 | - 关系仿函数 13 | - 逻辑仿函数 14 | 15 | 用法: 16 | - 这些仿函数产生的对象,用法和一般函数完全相同 17 | - 使用内建函数对象,需要引入头文件 18 | */ 19 | 20 | // 算数仿函数 21 | // 实现四则运算。其中negate是一元运算,其他都是二元运算 22 | /* 23 | - template T plus // 加法仿函数 24 | - template T minus // 减法仿函数 25 | - template T multiplies // 乘法仿函数 26 | - template T divides // 除法仿函数 27 | - template T modulus // 取模仿函数 28 | - template T negate // 取反仿函数 29 | */ 30 | 31 | void test01() 32 | { 33 | // 取反仿函数 34 | negate n; 35 | cout << n(50) << endl; 36 | } 37 | 38 | void test02() 39 | { 40 | plus p; 41 | cout << p(10, 10) << endl; 42 | } 43 | 44 | int main() 45 | { 46 | test01(); 47 | test02(); 48 | return 0; 49 | } -------------------------------------------------------------------------------- /Chapter_05_STL_函数对象/05_内建函数对象_关系仿函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // 关系仿函数 8 | // 实现关系对比 9 | /* 10 | - template bool equal_to // 等于 11 | - template bool not_equal_to // 不等于 12 | - template bool greater // 大于 13 | - template bool greater_equal // 大于等于 14 | - template bool less // 小于 15 | - template bool less_equal // 小于等于 16 | */ 17 | 18 | void printVector(vector &v) 19 | { 20 | for (vector::iterator it = v.begin(); it != v.end(); it++) 21 | { 22 | cout << *it << " "; 23 | } 24 | cout << endl; 25 | } 26 | 27 | class MyCompare 28 | { 29 | public: 30 | bool operator()(int v1, int v2) 31 | { 32 | return v1 > v2; 33 | } 34 | }; 35 | 36 | void test01() 37 | { 38 | vector v; 39 | v.push_back(30); 40 | v.push_back(50); 41 | v.push_back(20); 42 | v.push_back(10); 43 | v.push_back(40); 44 | printVector(v); 45 | 46 | // 实现降序排序 47 | // sort(v.begin(), v.end(), MyCompare()); 48 | sort(v.begin(), v.end(), greater()); // 等效于上一行 49 | printVector(v); 50 | } 51 | 52 | int main() 53 | { 54 | test01(); 55 | return 0; 56 | } -------------------------------------------------------------------------------- /Chapter_05_STL_函数对象/06_内建函数对象_逻辑仿函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // 逻辑仿函数 8 | // 实现逻辑运算 9 | /* 10 | - template bool logical_and // 逻辑与 11 | - template bool logical_or // 逻辑或 12 | - template bool logical_not // 逻辑非 13 | */ 14 | 15 | void printVector(const vector &v) 16 | { 17 | for (vector::const_iterator it = v.begin(); it != v.end(); it++) 18 | { 19 | cout << *it << " "; 20 | } 21 | cout << endl; 22 | } 23 | 24 | void test01() 25 | { 26 | vector v; 27 | v.push_back(true); 28 | v.push_back(false); 29 | v.push_back(true); 30 | v.push_back(false); 31 | printVector(v); 32 | 33 | // 利用逻辑非,将容器v搬运到容器v2中,并执行取反操作 34 | vector v2; 35 | v2.resize(v.size()); 36 | 37 | transform(v.begin(), v.end(), v2.begin(), logical_not()); 38 | printVector(v2); 39 | } 40 | 41 | int main() 42 | { 43 | test01(); 44 | return 0; 45 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/01_遍历_for_each.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // STL 常用算法 7 | /* 8 | - 算法主要由头文件 组成 9 | - 是所有STL头文件中最大的一个,包括比较、交换、查找、遍历、复制、修改等等 10 | - 体积很小,只包括几个在序列上进行简单数学运算的模板函数 11 | - 定义了一些模板类,用以声明函数对象 12 | */ 13 | 14 | // for_each 15 | /* 16 | for_each(iterator beg, iterator end, _func); 17 | 遍历算法,遍历容器元素 18 | beg 开始迭代器 19 | end 结束迭代器 20 | _func 函数或函数对象 21 | */ 22 | 23 | // 普通函数 24 | void print01(int val) 25 | { 26 | cout << val << endl; 27 | } 28 | 29 | // 仿函数 30 | class print02 31 | { 32 | public: 33 | void operator()(int val) 34 | { 35 | cout << val << endl; 36 | } 37 | }; 38 | 39 | void test01() 40 | { 41 | vector v; 42 | for (int i = 0; i < 10; i++) 43 | { 44 | v.push_back(i); 45 | } 46 | 47 | // for_each(v.begin(), v.end(), print01); 48 | for_each(v.begin(), v.end(), print02()); 49 | } 50 | 51 | int main() 52 | { 53 | test01(); 54 | return 0; 55 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/02_遍历_transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // transform: 搬运容器到另一个容器中 7 | /* 8 | transform(iterator beg1, iterator end1, tierator beg2, _func); 9 | beg1 源容器开始迭代器 10 | end1 源容器结束迭代器 11 | beg2 目标容器开始迭代器 12 | _func 函数或函数对象 13 | */ 14 | 15 | class Transform 16 | { 17 | public: 18 | int operator()(int v) 19 | { 20 | // return v; 21 | return v + 100; // 示例:可以在搬运元素时对元素进行一些运算 22 | } 23 | }; 24 | 25 | class MyPrint 26 | { 27 | public: 28 | void operator()(int val) 29 | { 30 | cout << val << endl; 31 | } 32 | }; 33 | 34 | void test01() 35 | { 36 | vector v; // 源容器 37 | for (int i = 0; i < 10; i++) 38 | { 39 | v.push_back(i); 40 | } 41 | 42 | vector vTarget; // 目标容器 43 | vTarget.resize(v.size()); // 目标容器提前开辟空间 44 | 45 | transform(v.begin(), v.end(), vTarget.begin(), Transform()); 46 | 47 | for_each(vTarget.begin(), vTarget.end(), MyPrint()); 48 | } 49 | 50 | int main() 51 | { 52 | test01(); 53 | return 0; 54 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/03_查找_find.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // find 7 | /* 8 | 查找指定元素,找到则返回指定元素的迭代器,找不到则返回结束迭代器end() 9 | 10 | find(iterator beg, iterator end, value); 11 | beg 开始迭代器 12 | end 结束迭代器 13 | value 查找的元素 14 | */ 15 | 16 | // 查找内置数据类型 17 | void test01() 18 | { 19 | vector v; 20 | for (int i = 0; i < 10; i++) 21 | { 22 | v.push_back(i); 23 | } 24 | vector::iterator it = find(v.begin(), v.end(), 5); 25 | // vector::iterator it = find(v.begin(), v.end(), 50); 26 | if (it == v.end()) 27 | { 28 | cout << "未找到" << endl; 29 | } 30 | else 31 | { 32 | cout << "找到了 " << *it << endl; 33 | } 34 | } 35 | 36 | // 查找自定义数据类型 37 | 38 | class Person 39 | { 40 | public: 41 | Person(string name, int age) 42 | { 43 | this->m_Name = name; 44 | this->m_Age = age; 45 | } 46 | 47 | // 重载 == 底层 find 知道如何对比 Person 数据类型 48 | bool operator==(const Person &p) 49 | { 50 | if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) 51 | { 52 | return true; 53 | } 54 | else 55 | { 56 | return false; 57 | } 58 | } 59 | 60 | string m_Name; 61 | int m_Age; 62 | }; 63 | 64 | void test02() 65 | { 66 | vector v; 67 | 68 | Person p1("a", 20); 69 | Person p2("b", 21); 70 | Person p3("c", 22); 71 | Person p4("d", 23); 72 | 73 | v.push_back(p1); 74 | v.push_back(p2); 75 | v.push_back(p3); 76 | v.push_back(p4); 77 | 78 | Person pp("b", 21); 79 | 80 | vector::iterator it = find(v.begin(), v.end(), pp); 81 | 82 | if (it == v.end()) 83 | { 84 | cout << "没有找到" << endl; 85 | } 86 | else 87 | { 88 | cout << "找到元素, 姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl; 89 | } 90 | } 91 | 92 | int main() 93 | { 94 | // test01(); 95 | test02(); 96 | return 0; 97 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/04_查找_find_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // find_if 7 | 8 | /* 9 | 按条件查找元素 10 | 11 | find_if(iterator beg, iterator end, _Pred); 12 | 按条件查找元素,找到返回指定位置迭代器,找不到返回结束迭代器 13 | beg 开始迭代器 14 | end 结束迭代器 15 | _Pred 函数或谓词 16 | 17 | */ 18 | 19 | // 查找内置数据类型 20 | 21 | class GreaterFive 22 | { 23 | public: 24 | bool operator()(int val) 25 | { 26 | return val > 5; 27 | } 28 | }; 29 | 30 | void test01() 31 | { 32 | vector v; 33 | for (int i = 0; i < 10; i++) 34 | { 35 | v.push_back(i); 36 | } 37 | 38 | vector::iterator it = find_if(v.begin(), v.end(), GreaterFive()); 39 | 40 | if (it == v.end()) 41 | { 42 | cout << "未找到" << endl; 43 | } 44 | else 45 | { 46 | cout << "找到大于5的数字为: " << *it << endl; 47 | } 48 | } 49 | 50 | // 查找自定义数据类型 51 | 52 | class Person 53 | { 54 | public: 55 | Person(string name, int age) 56 | { 57 | this->m_Name = name; 58 | this->m_Age = age; 59 | } 60 | 61 | // 重载 == 底层 find 知道如何对比 Person 数据类型 62 | bool operator==(const Person &p) 63 | { 64 | if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) 65 | { 66 | return true; 67 | } 68 | else 69 | { 70 | return false; 71 | } 72 | } 73 | 74 | string m_Name; 75 | int m_Age; 76 | }; 77 | 78 | class Greater21 79 | { 80 | public: 81 | bool operator()(Person &p) 82 | { 83 | return p.m_Age > 20; 84 | } 85 | }; 86 | 87 | void test02() 88 | { 89 | vector v; 90 | 91 | Person p1("a", 20); 92 | Person p2("b", 21); 93 | Person p3("c", 22); 94 | Person p4("d", 23); 95 | 96 | v.push_back(p1); 97 | v.push_back(p2); 98 | v.push_back(p3); 99 | v.push_back(p4); 100 | 101 | // 找年龄大于21的人 102 | vector::iterator it = find_if(v.begin(), v.end(), Greater21()); 103 | 104 | if (it == v.end()) 105 | { 106 | cout << "没有找到" << endl; 107 | } 108 | else 109 | { 110 | cout << "找到了,姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl; 111 | } 112 | } 113 | 114 | int main() 115 | { 116 | // test01(); 117 | test02(); 118 | return 0; 119 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/05_查找_adjacent_find.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // adjacent_find 7 | /* 8 | 查找相邻重复元素 9 | 10 | adjcent_find(iterator beg, iterator end); 11 | 查找相邻元素,返回相邻元素的第一个位置的迭代器 12 | beg 开始迭代器 13 | end 结束迭代器 14 | 15 | */ 16 | 17 | void test01() 18 | { 19 | vector v; 20 | 21 | v.push_back(0); 22 | v.push_back(2); 23 | v.push_back(0); 24 | v.push_back(3); 25 | v.push_back(1); 26 | v.push_back(4); 27 | v.push_back(3); 28 | v.push_back(3); 29 | 30 | vector::iterator pos = adjacent_find(v.begin(), v.end()); 31 | 32 | if (pos == v.end()) 33 | { 34 | cout << "未找到相邻重复元素" << endl; 35 | } 36 | else 37 | { 38 | cout << "找到相邻重复元素: " << *pos << endl; 39 | } 40 | } 41 | 42 | int main() 43 | { 44 | test01(); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/06_查找_binary_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // binary_search 二分查找法 7 | /* 8 | bool binary_search(iterator beg, tierator end, value); 9 | 查找指定的元素,查到返回true,否则返回false 10 | 注意:在无序序列中不可用 11 | beg 开始迭代器 12 | end 结束迭代器 13 | value 查找的元素 14 | 15 | */ 16 | 17 | void test01() 18 | { 19 | vector v; 20 | for (int i = 0; i < 10; i++) 21 | { 22 | v.push_back(i); 23 | } 24 | 25 | // v.push_back(2); // 如果是无序序列,则查找结果未必准确 26 | 27 | // 查找容器中是否有9 28 | bool ret = binary_search(v.begin(), v.end(), 9); 29 | if (ret) 30 | { 31 | cout << "找到了元素" << endl; 32 | } 33 | else 34 | { 35 | cout << "未找到" << endl; 36 | } 37 | } 38 | 39 | int main() 40 | { 41 | test01(); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/07_查找_count.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // count 7 | /* 8 | count(iterator beg, iterator end, value); 9 | 统计元素出现次数 10 | beg 开始迭代器 11 | end 结束迭代器 12 | value 统计的元素 13 | 14 | */ 15 | 16 | // 统计内置数据类型 17 | void test01() 18 | { 19 | vector v; 20 | v.push_back(10); 21 | v.push_back(40); 22 | v.push_back(30); 23 | v.push_back(40); 24 | v.push_back(10); 25 | v.push_back(40); 26 | 27 | int num = count(v.begin(), v.end(), 40); 28 | cout << "40 的元素个数为: " << num << endl; 29 | } 30 | 31 | // 统计自定义数据类型 32 | 33 | class Person 34 | { 35 | public: 36 | Person(string name, int age) 37 | { 38 | this->m_Name = name; 39 | this->m_Age = age; 40 | } 41 | 42 | // 重载 == 底层 find 知道如何对比 Person 数据类型 43 | bool operator==(const Person &p) const 44 | { 45 | if (this->m_Age == p.m_Age) 46 | { 47 | return true; 48 | } 49 | else 50 | { 51 | return false; 52 | } 53 | } 54 | 55 | string m_Name; 56 | int m_Age; 57 | }; 58 | 59 | void test02() 60 | { 61 | vector v; 62 | 63 | Person p1("a", 20); 64 | Person p2("b", 22); 65 | Person p3("c", 22); 66 | Person p4("d", 23); 67 | Person p5("e", 23); 68 | 69 | v.push_back(p1); 70 | v.push_back(p2); 71 | v.push_back(p3); 72 | v.push_back(p4); 73 | v.push_back(p5); 74 | 75 | Person pp("f", 22); 76 | 77 | int num = count(v.begin(), v.end(), pp); 78 | cout << num << endl; 79 | } 80 | 81 | int main() 82 | { 83 | // test01(); 84 | test02(); 85 | return 0; 86 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/08_查找_count_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // count_if 7 | /* 8 | 按条件统计元素个数 9 | 10 | count_if(iterator beg, iterator end, _Pred); 11 | 按条件统计元素出现次数 12 | beg 开始迭代器 13 | end 结束迭代器 14 | _Pred 谓词 15 | 16 | */ 17 | 18 | // 1、内置数据类型 19 | 20 | class Greater20 21 | { 22 | public: 23 | bool operator()(int val) 24 | { 25 | return val > 20; 26 | } 27 | }; 28 | 29 | void test01() 30 | { 31 | vector v; 32 | v.push_back(10); 33 | v.push_back(40); 34 | v.push_back(30); 35 | v.push_back(20); 36 | v.push_back(40); 37 | v.push_back(20); 38 | v.push_back(10); 39 | 40 | int num = count_if(v.begin(), v.end(), Greater20()); 41 | cout << "大于20元素个数为: " << num << endl; 42 | } 43 | 44 | // 2、自定义数据类型 45 | 46 | class Person 47 | { 48 | public: 49 | Person(string name, int age) 50 | { 51 | this->m_Name = name; 52 | this->m_Age = age; 53 | } 54 | 55 | string m_Name; 56 | int m_Age; 57 | }; 58 | 59 | class AgeGreater22 60 | { 61 | public: 62 | bool operator()(const Person &p) const 63 | { 64 | return p.m_Age > 22; 65 | } 66 | }; 67 | 68 | void test02() 69 | { 70 | vector v; 71 | Person p1("a", 20); 72 | Person p2("b", 21); 73 | Person p3("c", 22); 74 | Person p4("d", 23); 75 | Person p5("d", 24); 76 | 77 | v.push_back(p1); 78 | v.push_back(p2); 79 | v.push_back(p3); 80 | v.push_back(p4); 81 | v.push_back(p5); 82 | 83 | // 统计大于22的人数 84 | int num = count_if(v.begin(), v.end(), AgeGreater22()); 85 | cout << num << endl; 86 | } 87 | 88 | int main() 89 | { 90 | // test01(); 91 | test02(); 92 | return 0; 93 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/09_排序_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // sort 8 | /* 9 | 对容器内元素进行排序 10 | 11 | sort(iterator beg, iterator end, _Pred); 12 | 按值查找元素,找到返回指定位置迭代器,找不到返回结束位置迭代器 13 | beg 开始迭代器 14 | end 结束迭代器 15 | _Pred 谓词 16 | 17 | */ 18 | 19 | void myPrint(int val) 20 | { 21 | cout << val << endl; 22 | } 23 | 24 | void test01() 25 | { 26 | vector v; 27 | v.push_back(10); 28 | v.push_back(50); 29 | v.push_back(20); 30 | v.push_back(40); 31 | v.push_back(30); 32 | 33 | sort(v.begin(), v.end()); 34 | // for_each(v.begin(), v.end(), myPrint); 35 | 36 | // 改变为降序 37 | sort(v.begin(), v.end(), greater()); 38 | for_each(v.begin(), v.end(), myPrint); 39 | } 40 | 41 | int main() 42 | { 43 | test01(); 44 | return 0; 45 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/10_排序_random_shuffle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // random_shuffle 7 | /* 8 | 将指定范围内的元素随机调整次序(洗牌) 9 | 10 | random_shuffle(iterator beg, iterator end); 11 | beg 开始迭代器 12 | end 结束迭代器 13 | 14 | */ 15 | 16 | void myPrint(int val) 17 | { 18 | cout << val << endl; 19 | } 20 | 21 | void test01() 22 | { 23 | srand((unsigned int)time(NULL)); 24 | vector v; 25 | for (int i = 0; i < 10; i++) 26 | { 27 | v.push_back(i); 28 | } 29 | random_shuffle(v.begin(), v.end()); 30 | for_each(v.begin(), v.end(), myPrint); 31 | } 32 | 33 | int main() 34 | { 35 | test01(); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/11_排序_merge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // merge 7 | /* 8 | merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest); 9 | 将两个有序容器元素合并,并存储到另一容器中,且仍然是有序序列 10 | 注意:两个容器必须是有序的 11 | beg1 容器1开始迭代器 12 | end1 容器1结束迭代器 13 | beg2 容器2开始迭代器 14 | end2 容器2结束迭代器 15 | dest 目标容器开始迭代器 16 | 17 | */ 18 | 19 | void myPrint(int val) 20 | { 21 | cout << val << endl; 22 | } 23 | 24 | void test01() 25 | { 26 | vector v1; 27 | vector v2; 28 | for (int i = 0; i < 10; i++) 29 | { 30 | v1.push_back(i); 31 | v2.push_back(i + 1); 32 | } 33 | 34 | // 目标容器 35 | vector vTarget; 36 | vTarget.resize(v1.size() + v2.size()); 37 | 38 | merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); 39 | 40 | for_each(vTarget.begin(), vTarget.end(), myPrint); 41 | } 42 | 43 | int main() 44 | { 45 | test01(); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/12_排序_reverse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // reverse 7 | /* 8 | reverse(iterator beg, iterator end); 9 | 反转指定范围的元素 10 | beg 开始迭代器 11 | end 结束迭代器 12 | 13 | */ 14 | 15 | void myPrint(int val) 16 | { 17 | cout << val << "\t"; 18 | } 19 | 20 | void test01() 21 | { 22 | vector v; 23 | v.push_back(10); 24 | v.push_back(50); 25 | v.push_back(30); 26 | v.push_back(40); 27 | v.push_back(20); 28 | v.push_back(60); 29 | 30 | cout << "反转前:" << endl; 31 | for_each(v.begin(), v.end(), myPrint); 32 | cout << endl; 33 | 34 | reverse(v.begin(), v.end()); 35 | cout << "反转后:" << endl; 36 | for_each(v.begin(), v.end(), myPrint); 37 | cout << endl; 38 | } 39 | 40 | int main() 41 | { 42 | test01(); 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/13_拷贝与替换_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // copy 7 | /* 8 | copy(iterator beg, iterator end,iterator dest); 9 | 将容器内指定范围的元素拷贝到另一容器中 10 | beg 开始迭代器 11 | end 结束迭代器 12 | dest 目标起始迭代器 13 | 14 | */ 15 | 16 | void myPrint(int val) 17 | { 18 | cout << val << endl; 19 | } 20 | 21 | void test01() 22 | { 23 | vector v1; 24 | for (int i = 0; i < 10; i++) 25 | { 26 | v1.push_back(i); 27 | } 28 | 29 | vector v2; 30 | v2.resize(v1.size()); 31 | 32 | copy(v1.begin(), v1.end(), v2.begin()); 33 | 34 | for_each(v2.begin(), v2.end(), myPrint); 35 | } 36 | 37 | int main() 38 | { 39 | test01(); 40 | return 0; 41 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/14_拷贝与替换_replace.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // replace 7 | /* 8 | 将容器内指定范围的旧元素改为新元素 9 | 10 | replace(iterator beg, iterator end, oldvalue, newvalue); 11 | 将区间内旧元素替换为新元素 12 | beg 开始迭代器 13 | end 结束迭代器 14 | oldvalue 旧元素 15 | newvalue 新元素 16 | */ 17 | 18 | void myPrint(int val) 19 | { 20 | cout << val << endl; 21 | } 22 | 23 | void test01() 24 | { 25 | vector v; 26 | v.push_back(20); 27 | v.push_back(20); 28 | v.push_back(50); 29 | v.push_back(30); 30 | v.push_back(20); 31 | v.push_back(20); 32 | v.push_back(40); 33 | 34 | cout << "替换前:" << endl; 35 | for_each(v.begin(), v.end(), myPrint); 36 | 37 | // 将所有20替换为2000 38 | replace(v.begin(), v.end(), 20, 2000); 39 | cout << "替换后:" << endl; 40 | for_each(v.begin(), v.end(), myPrint); 41 | } 42 | 43 | int main() 44 | { 45 | test01(); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/15_拷贝与替换_replace_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // replace_if 7 | /* 8 | replace_if(iterator beg, iterator end, _pred, newvalue); 9 | 按条件替换元素,满足条件的替换成指定元素 10 | beg 开始迭代器 11 | end 结束迭代器 12 | _pred 谓词 13 | newvalue 替换的新元素 14 | */ 15 | 16 | class MyPrint 17 | { 18 | public: 19 | void operator()(int val) 20 | { 21 | cout << val << endl; 22 | } 23 | }; 24 | 25 | class MyGreater 26 | { 27 | public: 28 | bool operator()(int val) 29 | { 30 | return val >= 30; 31 | } 32 | }; 33 | 34 | void test01() 35 | { 36 | vector v; 37 | v.push_back(10); 38 | v.push_back(40); 39 | v.push_back(20); 40 | v.push_back(50); 41 | v.push_back(30); 42 | v.push_back(60); 43 | 44 | cout << "替换前:" << endl; 45 | for_each(v.begin(), v.end(), MyPrint()); 46 | 47 | // 将大于等于30的替换为3000 48 | replace_if(v.begin(), v.end(), MyGreater(), 3000); 49 | cout << "替换后:" << endl; 50 | for_each(v.begin(), v.end(), MyPrint()); 51 | } 52 | 53 | int main() 54 | { 55 | test01(); 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/16_拷贝与替换_swap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // swap 7 | /* 8 | swap(container c1, container c2); 9 | 互换两个容器的元素 10 | c1 容器1 11 | c2 容器2 12 | */ 13 | 14 | void myPrint(int val) 15 | { 16 | cout << val << " "; 17 | } 18 | 19 | void test01() 20 | { 21 | vector v1; 22 | vector v2; 23 | 24 | for (int i = 0; i < 10; i++) 25 | { 26 | v1.push_back(i); 27 | v2.push_back(i + 100); 28 | } 29 | 30 | cout << "交换前: " << endl; 31 | for_each(v1.begin(), v1.end(), myPrint); 32 | cout << endl; 33 | for_each(v2.begin(), v2.end(), myPrint); 34 | cout << endl; 35 | 36 | swap(v1, v2); 37 | 38 | cout << "交换后: " << endl; 39 | for_each(v1.begin(), v1.end(), myPrint); 40 | cout << endl; 41 | for_each(v2.begin(), v2.end(), myPrint); 42 | cout << endl; 43 | } 44 | 45 | int main() 46 | { 47 | test01(); 48 | return 0; 49 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/17_算数生成_accmulate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // accumulate 7 | /* 8 | accumulate(iterator beg, iterator end, value) 9 | 计算容器元素累计总和 10 | beg 开始迭代器 11 | end 结束迭代器 12 | value 起始值 13 | 14 | */ 15 | 16 | void test01() 17 | { 18 | vector v; 19 | for (int i = 0; i <= 100; i++) 20 | { 21 | v.push_back(i); 22 | } 23 | 24 | int sum = accumulate(v.begin(), v.end(), 0); 25 | cout << sum << endl; 26 | } 27 | 28 | int main() 29 | { 30 | test01(); 31 | return 0; 32 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/18_算数生成_fill.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // fill 8 | /* 9 | fill(iterator beg, iterator end, value); 10 | 向容器中填充元素 11 | beg 开始迭代器 12 | end 结束迭代器 13 | value 填充的值 14 | */ 15 | 16 | void myPrint(int val) 17 | { 18 | cout << val << endl; 19 | } 20 | 21 | void test01() 22 | { 23 | vector v; 24 | v.resize(10); 25 | fill(v.begin(), v.end(), 100); 26 | for_each(v.begin(), v.end(), myPrint); 27 | } 28 | 29 | int main() 30 | { 31 | test01(); 32 | return 0; 33 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/19_集合_set_intersection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // set_intersection 7 | /* 8 | set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest) 9 | 求两个集合的交集 10 | 注意两个集合必须是有序序列 11 | dest 目标容器的开始迭代器 12 | */ 13 | 14 | void test01() 15 | { 16 | vector v1; 17 | vector v2; 18 | 19 | for (int i = 0; i < 10; i++) 20 | { 21 | v1.push_back(i); // 0~9 22 | v2.push_back(i + 5); // 5~ 14 23 | } 24 | 25 | vector vTarget; 26 | // 对于交集运算,最极端情况为交集大小等于两容器中较小容器的大小 27 | vTarget.resize(min(v1.size(), v2.size())); 28 | 29 | vector::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); 30 | 31 | for (vector::iterator it = vTarget.begin(); it != itEnd; it++) 32 | { 33 | cout << *it << endl; 34 | } 35 | } 36 | 37 | int main() 38 | { 39 | test01(); 40 | return 0; 41 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/20_集合_set_union.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // set_union 7 | /* 8 | set_union(iterator beg1, iterator end1, iterator beg2, tierator end2, iterator dest); 9 | 求两个集合的并集 10 | 注意两个集合必须是有序序列 11 | dest 目标容器开始迭代器 12 | */ 13 | 14 | void test01() 15 | { 16 | vector v1; 17 | vector v2; 18 | 19 | for (int i = 0; i < 10; i++) 20 | { 21 | v1.push_back(i); 22 | v2.push_back(i + 5); 23 | } 24 | 25 | vector vTarget; 26 | vTarget.resize(v1.size() + v2.size()); 27 | 28 | vector::iterator itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); 29 | 30 | for (vector::iterator it = vTarget.begin(); it != itEnd; it++) 31 | { 32 | cout << *it << " "; 33 | } 34 | cout << endl; 35 | } 36 | 37 | int main() 38 | { 39 | test01(); 40 | return 0; 41 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/21_集合_set_difference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // set_difference 7 | /* 8 | set_difference(iterator beg1, iterator end1, iterator beg2, tierator end2, iterator dest); 9 | 求两个集合的差集 10 | 注意两个集合必须是有序序列 11 | dest 目标容器开始迭代器 12 | */ 13 | 14 | void test01() 15 | { 16 | vector v1; 17 | vector v2; 18 | 19 | for (int i = 0; i < 10; i++) 20 | { 21 | v1.push_back(i); 22 | v2.push_back(i + 5); 23 | } 24 | 25 | vector vTarget; 26 | vTarget.resize(max(v1.size(), v2.size())); 27 | 28 | vector::iterator itEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); 29 | cout << "v1 与 v2 差集为:" << endl; 30 | for (vector::iterator it = vTarget.begin(); it != itEnd; it++) 31 | { 32 | cout << *it << " "; 33 | } 34 | cout << endl; 35 | 36 | itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin()); 37 | cout << "v2 与 v1 差集为:" << endl; 38 | for (vector::iterator it = vTarget.begin(); it != itEnd; it++) 39 | { 40 | cout << *it << " "; 41 | } 42 | cout << endl; 43 | } 44 | 45 | int main() 46 | { 47 | test01(); 48 | return 0; 49 | } -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/22_案例_演讲比赛流程管理系统/main.cpp: -------------------------------------------------------------------------------- 1 | #include "speechManager.h" 2 | 3 | // 案例需求 4 | /* 5 | 比赛规则: 6 | - 一场演讲比赛,12人参加。比赛共两轮,第一轮为淘汰赛,第二轮为决赛。 7 | - 每名选手都有对应的编号,如 10001 ~ 10012 8 | - 比赛方式:分组比赛,每组6个人 9 | - 第一轮分为两个小组,整体按照选手编号进行抽签后顺序演讲 10 | - 十个评委分别给每名选手打分,去除最高分和最低分,求平均值作为本轮选手的成绩 11 | - 当小组演讲结束后,淘汰组内排名最后的三个选手,前三名晋级 12 | - 第二轮为决赛,前三名胜出 13 | - 每轮比赛后需要显示晋级选手的信息 14 | 15 | 程序功能: 16 | - 开始演讲比赛:完成整届比赛的流程,每个比赛阶段给用户一个提示 17 | - 查看往届记录:查看比赛前三名结果,每次比赛结果都会保存在csv文件中 18 | - 清空比赛记录:将文件中数据清空 19 | - 退出比赛程序:可以退出当前程序 20 | 21 | */ 22 | 23 | int main() 24 | { 25 | srand((unsigned int)time(NULL)); 26 | 27 | SpeechManager sm; 28 | int choice = 0; 29 | 30 | while (true) 31 | { 32 | sm.showMenu(); 33 | cout << "请输入选择: " << endl; 34 | cin >> choice; 35 | 36 | switch (choice) 37 | { 38 | case 1: // 开始比赛 39 | sm.startSpeech(); 40 | break; 41 | case 2: // 查看记录 42 | sm.showRecord(); 43 | break; 44 | case 3: // 清空记录 45 | sm.clearRecord(); 46 | break; 47 | case 0: // 退出系统 48 | sm.exitSystem(); 49 | break; 50 | 51 | default: 52 | system("clear"); 53 | break; 54 | } 55 | } 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/22_案例_演讲比赛流程管理系统/speaker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | 5 | class Speaker 6 | { 7 | public: 8 | string m_Name; 9 | double m_Score[2]; // 分数,最多有两轮得分 10 | }; 11 | -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/22_案例_演讲比赛流程管理系统/speech.csv: -------------------------------------------------------------------------------- 1 | 10008,84.925,10003,83.425,10006,79.8625, 2 | 10001,84.7,10009,80.5125,10003,80.25, 3 | -------------------------------------------------------------------------------- /Chapter_06_STL_常用算法/22_案例_演讲比赛流程管理系统/speechManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "speaker.h" 10 | 11 | using namespace std; 12 | 13 | // 设计演讲比赛管理类 14 | /* 15 | - 提供菜单界面与用户交互 16 | - 对演讲比赛流程进行控制 17 | - 与文件的读写交互 18 | */ 19 | 20 | class SpeechManager 21 | { 22 | public: 23 | SpeechManager(); 24 | 25 | ~SpeechManager(); 26 | 27 | // 比赛选手容器 12人 28 | vector v1; 29 | 30 | // 第一轮晋级容器 6人 31 | vector v2; 32 | 33 | // 胜利前三名容器 3人 34 | vector vVictory; 35 | 36 | // 存放编号以及对应的具体选手容器 37 | map m_Speaker; 38 | 39 | // 记录比赛轮数 40 | int m_Index; 41 | 42 | void showMenu(); 43 | 44 | // 退出系统 45 | void exitSystem(); 46 | 47 | // 初始化 48 | void initSpeech(); 49 | 50 | // 初始化创建12名选手 51 | void creatSpeaker(); 52 | 53 | // 开始比赛-比赛流程控制 54 | void startSpeech(); 55 | 56 | // 抽签 57 | void speechDraw(); 58 | 59 | // 比赛 60 | void speechContest(); 61 | 62 | // 显示得分 63 | void showScore(); 64 | 65 | // 保存记录 66 | void saveRecord(); 67 | 68 | // 读取记录 69 | void loadRecord(); 70 | 71 | // 文件为空的标志 72 | bool fileIsEmpty; 73 | 74 | // 往届记录 75 | map> m_Record; 76 | 77 | // 显示往届得分 78 | void showRecord(); 79 | 80 | // 清空记录 81 | void clearRecord(); 82 | }; 83 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/computerRoom.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | using namespace std; 4 | 5 | // 机房类 6 | class ComputerRoom 7 | { 8 | private: 9 | /* data */ 10 | public: 11 | int m_ComId; // 机房id号 12 | int m_MaxNum; // 机房最大容量 13 | }; 14 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/globalFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 管理员文件 4 | #define ADMIN_FILE "./records/admin.txt" 5 | 6 | // 学生文件 7 | #define STUDENT_FILE "./records/students.txt" 8 | 9 | // 教师文件 10 | #define TEACHER_FILE "./records/teachers.txt" 11 | 12 | // 机房信息文件 13 | #define COMPUTER_FILE "./records/computerRooms.txt" 14 | 15 | // 订单文件 16 | #define ORDER_FILE "./records/order.txt" 17 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/identity.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "globalFile.h" 6 | #include "computerRoom.h" 7 | 8 | using namespace std; 9 | 10 | // 身份抽象类 11 | class Identity 12 | { 13 | public: 14 | // 操作菜单 纯虚函数 15 | virtual void operMenu() = 0; 16 | 17 | string m_Name; // 用户名 18 | string m_Pwd; // 密码 19 | }; 20 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "identity.h" 3 | #include "student.h" 4 | #include "teacher.h" 5 | 6 | class Manager : public Identity 7 | { 8 | public: 9 | // 默认构造 10 | Manager(); 11 | 12 | // 有参构造 13 | Manager(string name, string pwd); 14 | 15 | // 选择菜单 16 | virtual void operMenu(); 17 | 18 | // 添加帐号 19 | void addPerson(); 20 | 21 | // 查看帐号 22 | void showPerson(); 23 | 24 | // 查看机房信息 25 | void showComputer(); 26 | 27 | // 清空预约记录 28 | void cleanFile(); 29 | 30 | // 检测重复 31 | bool checkRepeat(int id, int type); 32 | 33 | private: 34 | // 学生容器 35 | vector vStu; 36 | 37 | // 教师容器 38 | vector vTea; 39 | 40 | // 初始化容器 41 | void initVector(); 42 | 43 | // 机房容器 44 | vector vCom; 45 | }; -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/orderFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "globalFile.h" 7 | using namespace std; 8 | 9 | class OrderFile 10 | { 11 | public: 12 | OrderFile(); 13 | 14 | // 更新预约记录 15 | void updateOrder(); 16 | 17 | // 记录容器 key--记录的条数 value--记录具体信息的键值对 18 | map> m_orderData; 19 | 20 | // 预约记录条数 21 | int m_Size; 22 | }; 23 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/records/admin.txt: -------------------------------------------------------------------------------- 1 | admin 123 -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/records/computerRooms.txt: -------------------------------------------------------------------------------- 1 | 1 20 2 | 2 50 3 | 3 100 4 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/records/order.txt: -------------------------------------------------------------------------------- 1 | date:2 interval:2 stuId:1 stuName:张三 roomId:3 status:1 2 | date:5 interval:2 stuId:1 stuName:张三 roomId:3 status:1 3 | date:4 interval:1 stuId:1 stuName:张三 roomId:1 status:1 4 | date:3 interval:2 stuId:2 stuName:李四 roomId:2 status:1 5 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/records/students.txt: -------------------------------------------------------------------------------- 1 | 1 张三 123 2 | 2 李四 456 3 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/records/teachers.txt: -------------------------------------------------------------------------------- 1 | 1 老王 123 2 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/student.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "identity.h" 3 | #include "orderFile.h" 4 | 5 | class Student : public Identity 6 | { 7 | public: 8 | // 默认构造 9 | Student(); 10 | // 有参构造 11 | Student(int id, string name, string pwd); 12 | 13 | // 菜单界面 14 | virtual void operMenu(); 15 | 16 | // 申请预约 17 | void applyOrder(); 18 | 19 | // 查看自己的预约 20 | void showMyOrder(); 21 | 22 | // 查看所有预约 23 | void showAllOrder(); 24 | 25 | // 取消预约 26 | void cancelOrder(); 27 | 28 | // 学生学号 29 | int m_Id; 30 | 31 | private: 32 | // 机房容器 33 | vector vCom; 34 | 35 | // 获取机房信息 36 | void initVector(); 37 | }; 38 | -------------------------------------------------------------------------------- /Chapter_07_案例_机房预约系统/teacher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "identity.h" 3 | #include "orderFile.h" 4 | 5 | class Teacher : public Identity 6 | { 7 | public: 8 | // 默认构造 9 | Teacher(); 10 | 11 | // 有参构造 12 | Teacher(int empId, string name, string pwd); 13 | 14 | // 菜单界面 15 | virtual void operMenu(); 16 | 17 | // 查看所有预约 18 | void showAllOrder(); 19 | 20 | // 审核预约 21 | void validOrder(); 22 | 23 | int m_EmpId; // 教师编号 24 | }; 25 | -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/01_typed.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 模板起源: 3 | C++为静态类型语言,在效率与类型安全方面有极大优势。但这种语言也在很大程度上为程序员编写通用性更强的 4 | 代码带来瓶颈:即使是抽象层面一致的,也不得不为每一种数据类型各自编写一份(近乎)完全相同的代码实现 5 | */ 6 | 7 | #include 8 | using namespace std; 9 | 10 | int max_int(int x, int y) 11 | { 12 | return x > y ? x : y; 13 | } 14 | 15 | double max_double(double x, double y) 16 | { 17 | return x > y ? x : y; 18 | } 19 | 20 | string max_string(string x, string y) 21 | { 22 | return x > y ? x : y; 23 | } 24 | 25 | int main() 26 | { 27 | int nx = 10, ny = 20; 28 | cout << max_int(nx, ny) << endl; 29 | 30 | double dx = 12.3, dy = 45.6; 31 | cout << max_double(dx, dy) << endl; 32 | 33 | string sx = "world", sy = "hello"; 34 | cout << max_string(sx, sy) << endl; 35 | 36 | return 0; 37 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/02_untyped.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 宏可摆脱数据类型的限制: 3 | - 宏是在预处理阶段针对代码的纯文本替换 4 | - 宏本身没有函数的语义(不会对数据类型进行检查) 5 | - 因此借助参数宏虽然可以摆脱类型的约束和限制,但也同时丧失了对数据类型的检查 6 | */ 7 | 8 | #include 9 | using namespace std; 10 | 11 | #define Max(x, y) (x > y ? x : y) 12 | 13 | int main() 14 | { 15 | int nx = 10, ny = 20; 16 | cout << Max(nx, ny) << endl; 17 | // (nx > ny ? nx : ny) 18 | 19 | double dx = 12.3, dy = 45.6; 20 | cout << Max(dx, dy) << endl; 21 | 22 | string sx = "world", sy = "hello"; 23 | cout << Max(sx, sy) << endl; 24 | 25 | char cx[256] = "world", cy[256] = "hellow"; 26 | cout << Max(cx, cy) << endl; // 会出现错误 27 | // (cx>cy?cx:cy) 不是比较字符串大小,而是指针大小 28 | 29 | return 0; 30 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/03_macro.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 利用宏构建通用函数框架 3 | - 通过实例化宏,让预处理器将这个宏代换为针对不同数据类型的真正函数 4 | - 将宏的通用性和函数的类型安全性完美结合起来 5 | */ 6 | 7 | #include 8 | using namespace std; 9 | 10 | #define MAX(T) \ 11 | T max_##T(T x, T y) \ 12 | { \ 13 | return x > y ? x : y; \ 14 | } 15 | 16 | MAX(int) // 预编译器会将其替换为如下内容 17 | // int max_int(int x, int y) 18 | // { 19 | // return x > y ? x : y; 20 | // } 21 | 22 | MAX(double) 23 | // double max_double(double x, double y) 24 | // { 25 | // return x > y ? x : y; 26 | // } 27 | 28 | MAX(string) 29 | // 缺陷:代码可读性差,难以理解max_int()等函数的来历 30 | 31 | #define Max(T) max_##T // 小技巧,用于解决可读性问题 32 | 33 | int main() 34 | { 35 | int nx = 10, ny = 20; 36 | // cout << max_int(nx, ny) << endl; 37 | cout << Max(int)(nx, ny) << endl; 38 | 39 | double dx = 12.3, dy = 45.6; 40 | // cout << max_double(dx, dy) << endl; 41 | cout << Max(double)(dx, dy) << endl; 42 | 43 | string sx = "world", sy = "hello"; 44 | // cout << max_string(sx, sy) << endl; 45 | cout << Max(string)(sx, sy) << endl; 46 | 47 | char cx[256] = "wrold", cy[256] = "hello"; 48 | cout << Max(string)(cx, cy) << endl; // 会触发类型转换,也能正确处理了 49 | // max_string(cx, cy) 50 | 51 | return 0; 52 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/04_functmpl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 函数模板的定义 3 | - 函数模板的定义形式: 4 | template 5 | 返回值类型 函数模板名(调用形参1, 调用形参2, ...) 6 | { 7 | ...... 8 | } 9 | - 可以使用任何标识符作为类型形参的名称,出于习惯一般使用"T", 10 | "T" 表示调用者在使用这个函数模板时指定的任意数据类型 11 | 12 | 函数模板的使用 13 | - 使用函数模板必须对函数模板进行实例化 14 | - 形式:函数模板名<类型实参1, 类型实参2, ...>(调用参数1, ...); 15 | 16 | 函数模板的分析 17 | - 编译器并不是把函数模板编译成一个可以处理任何数据类型的单一实体 18 | - 编译器在实例化函数模板时根据类型实参从函数模板中产生一个真正的函数实体 19 | - 函数模板并不是一个函数实体,通过实例化才能产生真正的函数实体 20 | - 函数模板可以视为只是编译器产生函数实体的依据 21 | - 实例化:用具体数据类型替换函数模板类型形参的过程,这将产生一个函数模板的实例(函数实体) 22 | - 只要使用函数模板,就会自动引发编译器的实例化过程,程序员不需要额外请求对函数模板的实例化 23 | 24 | 实例化函数模板的条件 25 | - 原则上来说可以使用任何类型来实例化函数模板,不管其为基本类型还是类类型 26 | - 但前提是该类型必须支持函数模板所要执行的操作 27 | 28 | */ 29 | 30 | #include 31 | 32 | using namespace std; 33 | 34 | // 函数模板 35 | template 36 | T Max(T x, T y) 37 | { 38 | return x > y ? x : y; 39 | } 40 | 41 | // 自定义的类 42 | class Integer 43 | { 44 | public: 45 | Integer(int i) : m_i(i) {} 46 | bool operator>(Integer const &that) const 47 | { 48 | return m_i > that.m_i; 49 | } 50 | 51 | private: 52 | int m_i; 53 | }; 54 | 55 | int main() 56 | { 57 | int nx = 10, ny = 20; 58 | cout << Max(nx, ny) << endl; 59 | double dx = 12.3, dy = 45.6; 60 | cout << Max(dx, dy) << endl; 61 | string sx = "world", sy = "hello"; 62 | cout << Max(sx, sy) << endl; 63 | 64 | Integer ix = 100, iy = 200; 65 | Max(ix, iy); // 当Integer类实现了>之后就可以使用了 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/05_double_compile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 二次编译 3 | - 编译器对函数模板都会进行两次编译 4 | - 第一次编译发生在实例化函数模板之前(产生真正函数实体之前),只检查函数模板 5 | 本身内部代码,检查基本词法是否正确: 6 | 1. 函数模板内部出现的所有标识符是否均有声明 7 | 2. 对于已知类型的调用要查看调用是否有效 8 | 3. 对于未知类型的调用都认为合理 9 | - 第二次编译发生在实例化函数模板之后(产生真正函数实体之后), 10 | 结合所使用的类型实参,再次检查模板代码,查看所有调用是否真的均有效 11 | 12 | */ 13 | #include 14 | 15 | using namespace std; 16 | 17 | class A 18 | { 19 | public: 20 | void func() 21 | { 22 | cout << "A::func()" << endl; 23 | } 24 | }; 25 | 26 | template 27 | void foo() 28 | { 29 | // jklaqwij // 错误的标识符将在第一次编译时报错 30 | A a; 31 | a.func(); // 对已知类型的调用 32 | T t; 33 | t.qiojnkzx(); // 未知类型调用,在第一次编译时不会报错 34 | // t.qiojnk(); // 未知类型调用,但由于出现<>,会报错 35 | } 36 | 37 | int main() 38 | { 39 | // foo(); // 第二次编译会报错,没有成员qiojnkzx 40 | return 0; 41 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/06_deduction.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 隐式推断类型实参 3 | 4 | - 如果函数模板的调用形参与类型形参相关, 5 | - 那么在实例化函数模板时即使不显式指明函数模板的类型实参,编译器 6 | 也有能力根据调用实参的类型隐式推断出正确的类型实参的类型 7 | - 获得和调用普通函数一致的语法表现形式 8 | - 三种不能做隐式推断的情况: 9 | 1.调用参数 和 类型参数 不完全相关 10 | 2.隐式推断不支持隐式类型转换 11 | 3.返回值类型不支持隐式推断 12 | 13 | */ 14 | 15 | #include 16 | 17 | using namespace std; 18 | 19 | // 函数模板 20 | template 21 | T Max(T x, T y) 22 | { 23 | return x > y ? x : y; 24 | } 25 | 26 | template 27 | void Func(D x) 28 | { 29 | // 调用参数和类型参数不完全相关,无法隐式推断T的类型 30 | } 31 | 32 | template 33 | R Hum(T x) 34 | { 35 | R r; 36 | // 返回值类型不支持隐式推断 37 | return r; 38 | } 39 | 40 | int main() 41 | { 42 | int nx = 10, ny = 20; 43 | cout << Max<>(nx, ny) << endl; 44 | // Max(nx, ny) 45 | 46 | double dx = 12.3, dy = 45.6; 47 | cout << Max(dx, dy) << endl; 48 | // Max(dx, dy) 49 | 50 | string sx = "world", sy = "hello"; 51 | cout << Max(sx, sy) << endl; 52 | 53 | // Func(nx); // 调用参数和类型参数不完全相关,无法隐式推断T的类型 54 | Func(nx); 55 | // Func(nx) 56 | 57 | // Max(nx, dy); // 隐式推断不支持隐式类型转换 58 | Max(nx, (int)dy); 59 | 60 | // Hum(nx); // 返回值类型不支持隐式推断 61 | Hum(nx); 62 | 63 | return 0; 64 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/07_overload.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 函数模板的重载 3 | 4 | - 普通函数和可实例化出该函数的函数模板构成重载关系 5 | 在数据类型匹配度相同情况下编译器优先选择普通函数 6 | 除非函数模板可以产生具有更好的数据类型匹配度的实例 7 | - 函数模板的实例化不支持隐式类型转换,但普通函数支持 8 | 在传递参数时如果需要编译器做隐式类型转换,则编译器选择普通函数 9 | - 可以在实例化时用<>强行告知编译器选择函数模板 10 | */ 11 | 12 | #include 13 | 14 | using namespace std; 15 | 16 | void Max(int x, int y) 17 | { 18 | cout << "1: Max(int, int)" << endl; 19 | } 20 | 21 | template 22 | void Max(T x, T y) 23 | { 24 | cout << "2: Max(T, T)" << endl; 25 | } 26 | 27 | int main() 28 | { 29 | int nx = 10, ny = 20; 30 | Max(nx, ny); // 在数据类型匹配度相同情况下编译器优先选择普通函数 31 | 32 | double dx = 12.3, dy = 45.6; 33 | Max(dx, dy); // 除非函数模板可以产生具有更好的数据类型匹配度的实例 34 | Max(nx, dy); // 在传递参数时如果需要编译器做隐式类型转换,则编译器选择普通函数 35 | 36 | Max<>(nx, ny); // 可以在实例化时用<>强行告知编译器选择函数模板 37 | 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/08_clstmpl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 类模板的声明 3 | 4 | - 形式:template class 类模板名 {...}; 5 | 6 | - 如果在类模板外实现成员函数: 7 | temlpate 8 | 返回值类型 类模板名 <类型形参1, ...>::函数名(调用形参1, ...){ 函数体实现; } 9 | 10 | 类模板的使用(上) 11 | - 使用类模板必须对类模板进行实例化(产生真正的类) 12 | 类模板本身并不代表一个确定的类型(即不能用于定义对象),只有通过类型实参 13 | 实例化成真正的类后才具备类的语义(即可以定义对象) 14 | */ 15 | 16 | #include 17 | 18 | using namespace std; 19 | 20 | // 类模板 21 | template 22 | class CMath 23 | { 24 | public: 25 | CMath(T const &t1, T const &t2) : m_t1(t1), m_t2(t2) {} 26 | T add(); 27 | // T add() 28 | // { 29 | // return m_t1 + m_t2; 30 | // } 31 | 32 | private: 33 | T m_t1; 34 | T m_t2; 35 | }; 36 | 37 | // 在类模板外部写成员函数实现: 38 | template 39 | T CMath::add() 40 | { 41 | return m_t1 + m_t2; 42 | } 43 | 44 | int main() 45 | { 46 | int nx = 10, ny = 20; 47 | CMath m1(nx, ny); 48 | cout << m1.add() << endl; 49 | 50 | double dx = 12.3, dy = 45.6; 51 | CMath m2(dx, dy); 52 | cout << m2.add() << endl; 53 | 54 | string sx = "hello", sy = "world"; 55 | CMath m3(sx, sy); 56 | cout << m3.add() << endl; 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/09_clstmpl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 类模板的使用(下) 3 | - 类模板被实例化时类模板中的成员函数并没有被实例化,成员函数只有在被调用时 4 | 才会被实例化(即产生真正成员函数)注意:成员虚函数除外 5 | - 某些类型虽然并没有提供类模板所需要的全部功能,但照样可以实例化类模板, 6 | 只要不调用那些未提供功能的成员函数即可 7 | */ 8 | 9 | #include 10 | 11 | using namespace std; 12 | 13 | class Integer 14 | { 15 | public: 16 | Integer(int i) : m_i(i) {} 17 | 18 | Integer operator+(Integer const &that) const 19 | { 20 | return m_i + that.m_i; 21 | } 22 | 23 | private: 24 | int m_i; 25 | }; 26 | 27 | // 类模板 28 | template 29 | class CMath 30 | { 31 | public: 32 | CMath(T const &t1, T const &t2) : m_t1(t1), m_t2(t2) {} 33 | T add() 34 | { 35 | return m_t1 + m_t2; 36 | } 37 | 38 | private: 39 | T m_t1; 40 | T m_t2; 41 | }; 42 | 43 | /* 当编译器第一次读到 CMath 时,会将其实例化为如下内容: 44 | class CMath 45 | { 46 | public: 47 | private: 48 | int m_t1; 49 | int m_t2; 50 | }; 51 | 只有成员变量,没有成员函数 52 | 后续调用了哪个模板中的成员函数,实例中才出现对应的成员函数 53 | */ 54 | 55 | int main() 56 | { 57 | int nx = 10, ny = 20; 58 | CMath m1(nx, ny); 59 | cout << m1.add() << endl; 60 | 61 | Integer ix = 100, iy = 200; 62 | CMath m2(ix, iy); 63 | // Integer 类并不能实现类模板中的add(),但只要不调用就不会报错 64 | // m2.add(); // 一旦调用add(),则类实例中出现add(),报错 65 | m2.add(); // 修改Integer类,使其支持+运算符,即可使用了 66 | 67 | return 0; 68 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/10_static.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 类模板的静态成员 3 | 4 | - 类模板中的静态成员即不是每个对象拥有一份 5 | - 也不是类模板拥有一份 6 | - 而应该是由类模板实例化出的每一个真正的类各有一份 7 | - 且为该实例化类定义的所有对象共享 8 | */ 9 | 10 | #include 11 | 12 | using namespace std; 13 | 14 | template 15 | class A 16 | { 17 | public: 18 | static void print() 19 | { 20 | cout << "&m_i: " << &m_i << "\t" 21 | << "&m_t: " << &m_t << endl; 22 | } 23 | static int m_i; 24 | static T m_t; 25 | }; 26 | 27 | template 28 | int A::m_i = 0; 29 | 30 | template 31 | T A::m_t; // = ?? 32 | 33 | int main() 34 | { 35 | A x, y, z; 36 | x.print(); 37 | y.print(); 38 | z.print(); 39 | A::print(); 40 | 41 | cout << "====================" << endl; 42 | 43 | A m, n, t; 44 | m.print(); 45 | n.print(); 46 | t.print(); 47 | A::print(); 48 | 49 | return 0; 50 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/11_recursion.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 类模板的递归实例化 3 | 4 | - 可以使用任何类型来实例化类模板 5 | - 由类模板实例化产生的类也可以用来实例化类模板自身 6 | 这种做法称之为类模板的递归实例化 7 | - 通过这种方法可以构建空间上具有递归特性的数据结构(例如多维数组) 8 | */ 9 | 10 | #include 11 | 12 | using namespace std; 13 | 14 | template 15 | class Array 16 | { 17 | public: 18 | T &operator[](size_t i) 19 | { 20 | return m_arr[i]; 21 | } 22 | 23 | private: 24 | T m_arr[10]; 25 | }; 26 | 27 | /* 28 | int main() 29 | { 30 | Array a; 31 | for (int i = 0; i < 10; i++) 32 | { 33 | a[i] = i + 1; 34 | } 35 | 36 | for (int i = 0; i < 10; i++) 37 | { 38 | cout << a[i] << ' '; 39 | } 40 | cout << endl; 41 | 42 | return 0; 43 | } 44 | */ 45 | 46 | int main() 47 | { 48 | Array> m; 49 | for (int i = 0; i < 10; i++) 50 | { 51 | for (int j = 0; j < 10; j++) 52 | { 53 | m[i][j] = i + j; 54 | } 55 | } 56 | 57 | for (int i = 0; i < 10; i++) 58 | { 59 | for (int j = 0; j < 10; j++) 60 | { 61 | cout << m[i][j] << ' '; 62 | } 63 | cout << endl; 64 | } 65 | 66 | return 0; 67 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/12_special.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 类模板的全局特化 3 | 4 | - 全类特化:特化一个类模板可以特化该类模板所有的成员函数, 5 | 相当于重新写了一个针对某种特定数据类型的具体类 6 | 声明形式:template<> class 类模板名<类型参数1, ...>{...}; 7 | - 成员特化:可以只针对某部分成员函数进行特化 8 | 声明形式:template<> 返回值类型 类模板名<类型参数1, ...>::成员函数名(调用参数1, ...){...} 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | // 类模板 17 | template 18 | class CMath 19 | { 20 | public: 21 | CMath(T const &t1, T const &t2) : m_t1(t1), m_t2(t2) {} 22 | T add() 23 | { 24 | return m_t1 + m_t2; 25 | } 26 | 27 | private: 28 | T m_t1; 29 | T m_t2; 30 | }; 31 | 32 | /* 33 | // 全类特化 34 | template <> 35 | class CMath 36 | { 37 | public: 38 | CMath(char *const &t1, char *const &t2) : m_t1(t1), m_t2(t2) {} 39 | char *const add() 40 | { 41 | return strcat(m_t1, m_t2); 42 | } 43 | 44 | private: 45 | char *const m_t1; 46 | char *const m_t2; 47 | }; 48 | */ 49 | 50 | // 成员特化 51 | template <> 52 | char *const CMath::add() 53 | { 54 | return strcat(m_t1, m_t2); 55 | } 56 | 57 | int main() 58 | { 59 | int nx = 10, ny = 20; 60 | CMath m1(nx, ny); 61 | cout << m1.add() << endl; 62 | 63 | double dx = 12.3, dy = 45.6; 64 | CMath m2(dx, dy); 65 | cout << m2.add() << endl; 66 | 67 | string sx = "hello", sy = "world"; 68 | CMath m3(sx, sy); 69 | cout << m3.add() << endl; 70 | 71 | char cx[256] = "hello", cy[256] = " world"; 72 | CMath m4(cx, cy); 73 | cout << m4.add() << endl; 74 | 75 | return 0; 76 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/13_partial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 局部特化 3 | 4 | - 全局特化是对类模板中的某个/全部成员函数做特化;局部特化是对类模板中的部分类型参数做特化 5 | - 非必要,不做类模板的局部特化。因为特化版本过多容易引发编译器匹配歧义 6 | */ 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class CMath 14 | { 15 | public: 16 | static void foo() 17 | { 18 | cout << "1: CMath::foo" << endl; 19 | } 20 | }; 21 | 22 | // 局部特化 23 | template 24 | class CMath 25 | { 26 | public: 27 | static void foo() 28 | { 29 | cout << "2: CMath::foo" << endl; 30 | } 31 | }; 32 | // 局部特化 33 | template 34 | class CMath 35 | { 36 | public: 37 | static void foo() 38 | { 39 | cout << "3: CMath::foo" << endl; 40 | } 41 | }; 42 | // 局部特化 43 | template 44 | class CMath 45 | { 46 | public: 47 | static void foo() 48 | { 49 | cout << "4: CMath" << endl; 50 | } 51 | }; 52 | 53 | int main() 54 | { 55 | 56 | CMath::foo(); // 1: CMath::foo 57 | CMath::foo(); // 2: CMath::foo 58 | // CMath::foo(); // 2、3匹配程度相同,匹配歧义,会报错 59 | CMath::foo(); // 1: CMath::foo 60 | // CMath::foo(); // 匹配歧义 61 | 62 | return 0; 63 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/14_default.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 类型形参的缺省值 3 | 4 | - 类模板的类型形参可以带缺省值 5 | 实例化类模板时,如果提供了类型实参则用所提供的类型实参来实例化类模板, 6 | 如果没有提供类型实参则用相应的类型形参的缺省类型来实例化类模板 7 | - 如果类模板的某个类型形参带有缺省值,那么它后面的类型形参都必须带缺省值 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | template 16 | class CMath 17 | { 18 | public: 19 | void print() 20 | { 21 | cout << "m_t: " << typeid(m_t).name() << "\t" 22 | << "m_d: " << typeid(m_d).name() << endl; 23 | } 24 | 25 | private: 26 | T m_t; 27 | D m_d; 28 | }; 29 | 30 | int main() 31 | { 32 | CMath m; 33 | m.print(); 34 | 35 | CMath<> m2; 36 | m2.print(); 37 | 38 | return 0; 39 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/15_valparam.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 数值形式的模板参数 3 | 4 | - 类模板的模板形参并不限于类型参数,普通数值也可以作为模板的参数 5 | */ 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | template 12 | class Array 13 | { 14 | public: 15 | T &operator[](size_t i) 16 | { 17 | return m_arr[i]; 18 | } 19 | 20 | size_t size() 21 | { 22 | return S; 23 | } 24 | 25 | private: 26 | T m_arr[S]; 27 | }; 28 | 29 | int main() 30 | { 31 | Array a; 32 | for (int i = 0; i < a.size(); i++) 33 | { 34 | a[i] = i + 1; 35 | } 36 | 37 | for (int i = 0; i < a.size(); i++) 38 | { 39 | cout << a[i] << ' '; 40 | } 41 | cout << endl; 42 | return 0; 43 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/16_membervar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 模板技巧 3 | 4 | - 模板型成员变量 5 | 成员变量,但其类型是由一个类模板实例化的未知类 6 | */ 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class Array 14 | { 15 | public: 16 | T &operator[](size_t i) 17 | { 18 | return m_arr[i]; 19 | } 20 | 21 | private: 22 | T m_arr[10]; 23 | }; 24 | 25 | // 求和器 26 | template 27 | class Sum 28 | { 29 | public: 30 | Sum(Array &s) : m_s(s) {} 31 | D add() 32 | { 33 | // 求和 34 | D d = 0; 35 | for (int i = 0; i < 10; i++) 36 | { 37 | d += m_s[i]; 38 | } 39 | return d; 40 | } 41 | 42 | private: 43 | Array m_s; // 模板型成员变量 44 | }; 45 | 46 | int main() 47 | { 48 | Array a; 49 | for (int i = 0; i < 10; i++) 50 | { 51 | a[i] = i + 1; 52 | } 53 | Sum s(a); 54 | cout << s.add() << endl; 55 | 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/17_memberfunc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 模板技巧 3 | 4 | - 模板型成员函数 5 | 类模板的成员函数模板 6 | */ 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class CMath 14 | { 15 | public: 16 | /* 17 | template 18 | void foo() // 成员 函数模板 19 | { 20 | cout << "CMath::foo()" << endl; 21 | } 22 | */ 23 | template 24 | void foo(); 25 | }; 26 | 27 | template 28 | template 29 | void CMath::foo() 30 | { 31 | cout << "CMath::foo()" << endl; 32 | } 33 | 34 | int main() 35 | { 36 | CMath m; 37 | m.foo(); 38 | 39 | return 0; 40 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/18_membertype.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 模板技巧 3 | 4 | - 模板型成员类型 5 | 类模板中嵌套的类模板 6 | */ 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class A 14 | { 15 | public: 16 | template 17 | class B 18 | { 19 | public: 20 | template 21 | class C; 22 | }; 23 | }; 24 | 25 | template 26 | template 27 | template 28 | class A::B::C 29 | { 30 | public: 31 | template 32 | void foo() 33 | { 34 | cout << "foo()" << endl; 35 | } 36 | }; 37 | 38 | int main() 39 | { 40 | A::B::C c; 41 | c.foo(); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/19_tmplargs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 模板技巧 3 | 4 | - 模板型模板参数 5 | 类模板的模板形参也可以是类模板,可以有缺省值 6 | */ 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | template 13 | class Array 14 | { 15 | public: 16 | T &operator[](size_t i) 17 | { 18 | return m_arr[i]; 19 | } 20 | 21 | private: 22 | T m_arr[10]; 23 | }; 24 | 25 | // 求和器 26 | template class C> 27 | class Sum 28 | { 29 | public: 30 | Sum(C &s) : m_s(s) {} 31 | D add() 32 | { 33 | // 求和 34 | D d = 0; 35 | for (int i = 0; i < 10; i++) 36 | { 37 | d += m_s[i]; 38 | } 39 | return d; 40 | } 41 | 42 | private: 43 | C m_s; // 模板型成员变量 44 | }; 45 | 46 | int main() 47 | { 48 | Array a; 49 | for (int i = 0; i < 10; i++) 50 | { 51 | a[i] = i + 1; 52 | } 53 | Sum s(a); 54 | cout << s.add() << endl; 55 | 56 | return 0; 57 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/20_nested_dependency.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 常见错误:嵌套依赖 3 | 4 | - 问题:由于模板要经过两次编译,在第一次编译模板的代码时,类型形参的具体 5 | 类型尚不明确,编译器将把类型形参的嵌套类型理解为某个未知类型的静态成员变 6 | 量,因此编译器会报错 7 | - 解决方法:在类型形参的前面添加一个 typename 标识符,意在告诉编译器 8 | 其后是一个类模板的嵌套使用 9 | */ 10 | 11 | #include 12 | 13 | using namespace std; 14 | 15 | class A 16 | { 17 | public: 18 | class B 19 | { 20 | public: 21 | void foo() 22 | { 23 | cout << "A::B::foo()" << endl; 24 | } 25 | }; 26 | }; 27 | 28 | template 29 | void Func() 30 | { 31 | // T::B b; // 嵌套依赖,报错 32 | typename T::B b; 33 | b.foo(); 34 | } 35 | 36 | int main() 37 | { 38 | Func(); 39 | return 0; 40 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/21_temperror.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 常见错误:依赖模板参数访问成员函数模板 3 | 4 | - 问题:利用未知类定义的对象来访问成员函数模板时,编译器在第一次编译时无法 5 | 解析成员函数模板的类型参数列表的<>而报告编译错误 6 | - 解决方法:在成员函数模板之前增加template关键字,意在告诉编译器其后是一个 7 | 函数模板实例,编译器就可以正确理解<>了。 8 | */ 9 | 10 | #include 11 | using namespace std; 12 | 13 | class A 14 | { 15 | public: 16 | template 17 | void foo() 18 | { 19 | cout << "A::foo()" << endl; 20 | } 21 | }; 22 | 23 | template 24 | void Func() 25 | { 26 | D d; 27 | // d.foo(); // 依赖模板参数访问成员函数模板 28 | d.template foo(); 29 | } 30 | 31 | int main() 32 | { 33 | Func(); 34 | return 0; 35 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/22_this.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 常见问题:子模板访问基类模板 3 | 4 | - 问题:在子类模板中访问基类模板的成员,编译器第一次编译时只在子类模板和 5 | 全局域中搜索使用的标识符号,不会到基类模板中搜索 6 | - 解决:在子类模板中可以通过使用作用域限定符或显示使用this指针 7 | */ 8 | 9 | #include 10 | using namespace std; 11 | 12 | template 13 | class Base 14 | { 15 | public: 16 | int m_i; 17 | void foo() 18 | { 19 | cout << "Base::foo()" << endl; 20 | } 21 | }; 22 | 23 | template 24 | class Derived : public Base 25 | { 26 | public: 27 | void bar() 28 | { 29 | Base::m_i = 100; 30 | // Base::foo(); 31 | this->foo(); 32 | } 33 | }; 34 | 35 | int main() 36 | { 37 | Derived d; 38 | d.bar(); 39 | return 0; 40 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/23_init.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 常见问题:零值初始化 3 | 4 | - 问题:基本数据类型不存在缺省构造函数,未被初始化的局部变量都具有一个不确定 5 | 的值。类类型由于存在缺省构造函数,在未被初始化的情况下可以有一个确定的缺省 6 | 初始化状态。基于以上两点,就会在模板实现中产生不一致的语法语义 7 | - 解决:如果希望模板中所有类型参数的变量,无论是类类型还是基本类型都以缺省方 8 | 式获得初始化,就必须对其进行显式的缺省构造 T() 9 | */ 10 | 11 | #include 12 | using namespace std; 13 | 14 | class Integer 15 | { 16 | public: 17 | Integer() : m_i(0) {} 18 | 19 | private: 20 | int m_i; 21 | friend ostream &operator<<(ostream &os, Integer const &that); 22 | }; 23 | 24 | ostream &operator<<(ostream &os, Integer const &that) 25 | { 26 | return os << that.m_i; 27 | } 28 | 29 | template 30 | void Func() 31 | { 32 | // T t; // 语义不一致,可能导致行为异常 33 | T t = T(); // 对于类取无参构造;对于基本类型取0值 34 | cout << "t=" << t << endl; 35 | } 36 | 37 | int main() 38 | { 39 | Func(); 40 | Func(); 41 | return 0; 42 | } -------------------------------------------------------------------------------- /Chapter_08_模板_进阶/24_virtual.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 类模板中的成员虚函数 3 | 4 | - 类模板中的普通成员函数可以是虚函数 5 | 即可以为类定义成员虚函数,和普通类的成员虚函数一样,类模板的成员虚函数 6 | 也可以表现出多态性 7 | - 类模板中的成员函数模板不可以是虚函数 8 | 根据成员虚函数的多态机制,需要一个虚函数表(表中保存成员虚函数的入口地址), 9 | 而这个表是编译器在实例化类模板时就产生,类的成员函数模板的实例化(即产生真 10 | 正的函数实体)需要编译器处理完调用后才会完成,这时才出现成员虚函数的地址 11 | - 总结:成员函数模板的延迟编译阻碍了虚函数表的静态构建 12 | */ 13 | 14 | #include 15 | using namespace std; 16 | 17 | template 18 | class Base 19 | { 20 | public: 21 | virtual void foo() 22 | { 23 | cout << "Base::foo()" << endl; 24 | } 25 | }; 26 | 27 | template 28 | class Derived : public Base 29 | { 30 | public: 31 | void foo() 32 | { 33 | cout << "Derived::foo()" << endl; 34 | } 35 | 36 | // virtual template 37 | // void bar() 38 | // { 39 | // } 40 | }; 41 | 42 | int main() 43 | { 44 | Derived d; 45 | Base *pBase = &d; 46 | pBase->foo(); 47 | return 0; 48 | } --------------------------------------------------------------------------------