C++的学习第三部分
一、模板
模板:C++的编译期代码生成机制,通过参数化类型实现泛型编程,允许编写与类型无关的通用代码。
模板的特点:
泛型编程和模板机制:
泛型编程:一种以类型参数化为核心的编程范式,通过模板机制编写与具体数据类型无关的通用算法和数据结构,实现代码复用且不牺牲运行时性能。
1、函数模板
函数模板:C++中用于生成重载函数的编译期蓝图,通过参数化类型让同一算法适用于不同数据类型,在调用时根据实参自动推导或显式实例化具体函数版本。
函数模板的语法:
总结:
注意事项:
①自动类型推导,必须推导出一致的数据类型T才可以使用。
template <typename TYPE> void my_swap(TYPE &a, TYPE &b) { TYPE num; num = a; a = b; b = num; } int main() { int a = 1; double c = 3.1; my_swap(a, c); // ❌ a是int类型,c是double类型,不可以使用模板。 system("pause"); return 0; }②模板必须要确定T的数据类型才可以使用。
template <typename TYPE> void fun() { cout << "fun()函数调用" << endl; } int main() { fun(); // ❌ TYPE类型未确定,不可以使用模板。 fun<int>(); // ✅ TYPE类型是int,TYPE类型确定了,可以使用模板。 system("pause"); return 0; }2、函数模板的案例
案例描述:
3、普通函数和函数模版的区别
如果函数模板的参数是引用,也不会发生隐式转换,因为引用不允许改变它的指向,也就是引用绑定的对象不能变。
总结:
4、普通函数和函数模版的调用规则
调用规则:
(1)普通函数和函数模板都可以实现,优先调用普通函数。
注意⚠️:在普通函数和函数模板都可以实现的时候,如果普通函数只有声明,没有定义,那么调用函数时,并不是调用函数模板,还是按照优先调用普通函数的规则,又因为普通函数没有实现,直接报错误信息。
(2)通过空模板参数列表(<>)可以强制调用函数模板。
![]()
(3)函数模板也可以重载。
(4)函数模板可以更好的匹配,优先调用函数模板。
总结:
5、模板的局限性
局限性:模板不是万能的,有些特定的数据类型需要具体化方式进行特殊的实现。
总结:
6、类模板
类模板:一种代码蓝图,允许你定义一个通用类,其中数据类型作为参数,在实例化时再指定具体类型(如vector<int>)
语法:
总结:
7、类模板与函数模板的区别
(1)类模板不可以自动类型推导
(2)类模板的参数列表可以有默认参数
8、类模板中成员函数的创建时机
类模板成员函数未调用不创建
类模板成员函数调用时创建
9、类模板对象做函数参数
类模板对象传参的方式:
(1)指定传入的类型:直接显示对象的数据类型
(2)参数模板化:对象中的参数变为模板进行传递
(3)整个类模板化:对象类型模板化进行传递
总结:
10、类模板与继承
指定具体的父类模板类型
子类也使用模板
总结:
11、类模板成员函数类外实现
总结:
12、类模板分文件编写
问题:
解决:
(1)直接包含cpp源文件
person.h:
person.cpp:
main.cpp:
(2)声明和实现在同一个文件中,文件名为.hpp
person.hpp:
main.cpp:
总结:
13、类模板与友元
(1)类内实现
(2)类外实现
总结:
14、类模板的案例
案例描述:实现一个通用数组类
案例测试:
My_Array.hpp:
main.cpp:
测试结果:
案例的完整实现:
My_Array.hpp:
#include "My_Array.hpp" #include <string> void print_array(MyArray<int>& arr) { for (int i = 0; i < arr.get_array_size(); i++) { cout << arr[i] << " "; } cout << endl; } void test() { cout << "---数组类模板测试---" << endl; // arr1的数组 MyArray<int> arr1(5); // 尾插 for (int i = 0; i < 5; i++) { arr1.Push_Back(i); } cout << "arr1的输出:"; print_array(arr1); // 容量和大小 cout << "arr1的容量:" << arr1.get_array_capacity() << endl; cout << "arr1的大小:" << arr1.get_array_size() << endl; // 拷贝构造 MyArray<int> arr2(arr1); cout << "arr2的输出:"; print_array(arr2); // 赋值 MyArray<int> arr3(5); arr3 = arr1; cout << "arr3的输出:"; print_array(arr3); // 尾删 arr2.Pop_Back(); cout << "arr2尾删后" << endl; cout << "arr2的容量:" << arr2.get_array_capacity() << endl; cout << "arr2的大小:" << arr2.get_array_size() << endl; cout << "arr2的输出:"; print_array(arr2); } // 自定义数据类型 class Person { public: Person() {} Person(string name, int age):m_name(name),m_age(age) {} string m_name; int m_age; }; void print_person(MyArray<Person> &arr) { for (int i = 0; i < arr.get_array_size(); i++) { cout << "姓名:" << arr[i].m_name << endl; cout << "年龄:" << arr[i].m_age << endl; } } void test2() { cout << "---自定义数据类型测试---" << endl; // 数组类模板存储的数据是Person类型 MyArray<Person> arr(5); Person p1("张三", 20); Person p2("李四", 22); Person p3("王五", 25); Person p4("孙悟空", 18); Person p5("猪八戒", 21); // 插入 arr.Push_Back(p1); arr.Push_Back(p2); arr.Push_Back(p3); arr.Push_Back(p4); arr.Push_Back(p5); // 输出打印 print_person(arr); // 修改元素 //Person p6("唐僧", 30); arr[0] = Person("唐僧", 30); cout << "arr[0]" << endl; cout << "姓名:" << arr[0].m_name << endl; cout << "年龄:" << arr[0].m_age << endl; // 容量和大小 cout << "arr的容量:" << arr.get_array_capacity() << endl; cout << "arr的大小:" << arr.get_array_size() << endl; } int main() { test(); test2(); system("pause"); return 0; }main.cpp:
#include "My_Array.hpp" #include <string> void print_array(MyArray<int>& arr) { for (int i = 0; i < arr.get_array_size(); i++) { cout << arr[i] << " "; } cout << endl; } void test() { cout << "---数组类模板测试---" << endl; // arr1的数组 MyArray<int> arr1(5); // 尾插 for (int i = 0; i < 5; i++) { arr1.Push_Back(i); } cout << "arr1的输出:"; print_array(arr1); // 容量和大小 cout << "arr1的容量:" << arr1.get_array_capacity() << endl; cout << "arr1的大小:" << arr1.get_array_size() << endl; // 拷贝构造 MyArray<int> arr2(arr1); cout << "arr2的输出:"; print_array(arr2); // 赋值 MyArray<int> arr3(5); arr3 = arr1; cout << "arr3的输出:"; print_array(arr3); // 尾删 arr2.Pop_Back(); cout << "arr2尾删后" << endl; cout << "arr2的容量:" << arr2.get_array_capacity() << endl; cout << "arr2的大小:" << arr2.get_array_size() << endl; cout << "arr2的输出:"; print_array(arr2); } // 自定义数据类型 class Person { public: Person() {} Person(string name, int age):m_name(name),m_age(age) {} string m_name; int m_age; }; void print_person(MyArray<Person> &arr) { for (int i = 0; i < arr.get_array_size(); i++) { cout << "姓名:" << arr[i].m_name << endl; cout << "年龄:" << arr[i].m_age << endl; } } void test2() { cout << "---自定义数据类型测试---" << endl; // 数组类模板存储的数据是Person类型 MyArray<Person> arr(5); Person p1("张三", 20); Person p2("李四", 22); Person p3("王五", 25); Person p4("孙悟空", 18); Person p5("猪八戒", 21); // 插入 arr.Push_Back(p1); arr.Push_Back(p2); arr.Push_Back(p3); arr.Push_Back(p4); arr.Push_Back(p5); // 输出打印 print_person(arr); // 修改元素 //Person p6("唐僧", 30); arr[0] = Person("唐僧", 30); cout << "arr[0]" << endl; cout << "姓名:" << arr[0].m_name << endl; cout << "年龄:" << arr[0].m_age << endl; // 容量和大小 cout << "arr的容量:" << arr.get_array_capacity() << endl; cout << "arr的大小:" << arr.get_array_size() << endl; } int main() { test(); test2(); system("pause"); return 0; }结果:
二、STL初识
STL:C++中一套由容器、迭代器、算法和函数对象组成的通用模板库,提供了高效、可复用的数据结构和算法。
STL的诞生:
1、STL的基本概念
STL的六大组件:
STL的容器、算法、迭代器:
(1)容器
(2)算法
(3)迭代器
迭代器的种类:
2、vector
(1)存放内置数据类型
(2)存放自定义数据类型
(3)存放自定义数据类型的指针
3、vector容器嵌套容器
三、STL的常用容器
1、string容器
(1)string构造函数
(2)string赋值操作
①string& operator=(const char *s);
②string& operator=(const string &s);
③string& operator=(char c);
④string& assign(const char *s);
⑤string& assign(const char *s, int n);
⑥string& assign(const string &s);
⑦string& assign(int n, char c);
(3)string字符串拼接
①string& operator+=(const char* str);
②string& operator+=(const char c);
③string& operator+=(const string& str);
④string& append(const char *s);
⑤string& append(const char *s, int n);
⑥string& append(const string &s);
⑦string& append(const string &s, int pos, int n);
(4)string查找和替换
查找:
替换:
(5)string字符串比较
比较方式:字符串比较按照字符的ASCII码对比。(=返回0,>返回1,<返回-1)
(6)string字符存取
string的单个字符存取:
(7)string插入和删除
(8)string子串
2、vector容器
功能:
vector与普通数组的区别:
动态扩展:
(1)vector构造函数
(2)vector赋值操作
①vector& operator=(const vector &vec);
②assign(beg,end);
③assign(n,elem);
(3)vector的容量和大小
resize(指定大小)若指定的更大,默认0填充,重载版本指定填充数值;若指定的更小,多余的删除。
总结:
(4)vector插入和删除
(5)vector数据存取
(6)vector互换容器
①使用示例
②实际用途
巧用swap收缩内存空间
(7)vector预留空间
没有reserve() 预留空间:
reserve() 预留空间:
3、deque容器
功能:
deque和vector的区别:
deque工作原理:
deque容器的迭代器也支持随机访问。
(1)deque构造函数
(2)deque赋值操作
①deque& operator=(const deque &deq);
②assign(beg,end);
③assign(n,elem);
(3)deque大小操作
(4)deque插入和删除
(5)deque数据存取
(6)deque排序操作
4、STL的案例1 - 评委打分
案例描述:
实现步骤:
结果:
5、stack容器
(1)基本概念
stack:先进后出的数据结构,只有一个出口。
栈中只有栈顶元素可被使用,不允许遍历行为。
(2)stack常用接口
总结:
6、queue容器
(1)基本概念
queue:先进先出的数据结构,有两个出口。
(2)queue常用接口
总结:
7、list容器
(1)基本概念
链表和结点
链表的存储方式不是连续的内存空间,因此链表的迭代器只支持前移和后移(只能一个一个递增或递减,不能跳跃几个递增或递减),属于双向迭代器。
优点和缺点
(2)list构造函数
(3)list的赋值和交换
(4)list大小操作
总结:
(5)list插入和删除
总结:
(6)list数据存取
总结:
(7)list反转和排序
总结:
(8)list排序案例
总结:
8、set容器
set容器:所有元素在插入时会自动排序
本质:
(1)set构造和赋值
总结:
(2)set大小和交换
总结:
(3)set插入和删除
总结:
(4)set查找和统计
总结:
(5)set和multiset的区别
总结:
(6)pair对组的创建
功能:
两种创建方式:
(7)set容器排序
①内置类型指定排序规则
②自定义数据类型指定排序规则
总结:
9、map容器
概念:
本质:
优点:
(1)map构造和赋值
(2)map大小和交换
总结:
(3)map插入和删除
总结:
(4)map查找和统计
总结:
(5)map容器排序
总结:
10、STL案例2 - 员工分组
案例描述:
实现步骤:
四、STL函数对象
1、函数对象概念
概念:
本质:
2、函数对象的使用
特点:
(1)函数对象在使用时,像普通函数一样调用,有参数也有返回值。
(2)函数对象超出普通函数的概念,函数对象可以有自己的状态。
(3)函数对象可作为参数传递
3、谓词
(1)一元谓词
(2)二元谓词
4、内建函数对象
(1)算术仿函数
(2)关系仿函数
(3)逻辑仿函数
五、STL常用算法
1、常用遍历算法
(1)for_each
(2)transform
2、常用查找算法
(1)find
(2)find_if
①内置数据类型
②自定义数据类型
(3)adjacent_find
(4)binary_search
无序序列进行binary_search查找,结果未知,所以必须是有序序列才可正确查找。
(5)count
①内置数据类型
②自定义数据类型
(6)count_if
①内置数据类型
②自定义数据类型
3、常用排序算法
(1)sort
(2)random_shuffle
(3)merge
(4)reverse
4、常用拷贝和替换算法
(1)copy
(2)replace
(3)replace_if
(3)swap
5、常用算术生成算法
(1)accumulate
(2)fill
6、常用集合算法
(1)set_intersection
(2)set_union
(3)set_difference
六、演讲比赛流程管理系统
有待解锁。。。
七、机房预约系统
有待解锁。。。
