C++的学习第三部分

一、模板

模板:C++的编译期代码生成机制,通过参数化类型实现泛型编程,允许编写与类型无关的通用代码。

模板的特点:

泛型编程和模板机制:

泛型编程:一种以类型参数化为核心的编程范式,通过模板机制编写与具体数据类型无关的通用算法和数据结构,实现代码复用且不牺牲运行时性能。

1、函数模板

函数模板:C++中用于生成重载函数的编译期蓝图,通过参数化类型让同一算法适用于不同数据类型,在调用时根据实参自动推导或显式实例化具体函数版本。

函数模板的语法:

总结:

注意事项:

①自动类型推导,必须推导出一致的数据类型T才可以使用。

cpp 复制代码
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的数据类型才可以使用。

cpp 复制代码
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:

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;
}

main.cpp:

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

无序序列进行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

六、演讲比赛流程管理系统

有待解锁。。。

七、机房预约系统

有待解锁。。。

相关推荐
码匠许师傅9 小时前
【C++ 面试真题】聊聊 C++ 的移动语义与右值引用
java·c++·面试
2603_965148119 小时前
如何解析JSON数据?API返回的商品信息处理教程
开发语言·数据库·python·自动化·json·api
小席是个热心肠10 小时前
AI相关的自我学习
java·人工智能·学习
小小龙学IT11 小时前
DuckDB 深度实战:用 C++ 在进程内跑一个「分析型数据库」
数据库·c++
知无不研12 小时前
lambda表达式的使用(3)
开发语言·c++·lambda
何事误红尘12 小时前
Mqtt学习笔记(一):Mosquitto服务器搭建、MQTTX安装测试
学习
cfm_291412 小时前
SpringAI + Ollama 本地大模型
java·开发语言·人工智能·语言模型
青山是哪个青山12 小时前
LangChain 学习笔记(三):LangSmith 调试与监控
笔记·学习·langchain
C++ 老炮儿的技术栈14 小时前
基于Qt实现轻量化本地音乐播放器
开发语言·c++·qt·c·播放器·音乐