C++模板编程—学习C++类库的编程基础


课程总目录


文章目录


一、详解函数模板

模板的意义:对类型也可以进行参数化了

cpp 复制代码
// 也可以用template<class T>,但class容易和类混淆,我们都用typename
template<typename T>	// 模板参数列表
bool compare(T a, T b)	// compare是一个函数模板
{
	cout << "template compare" << endl;
	return a > b;
}

/*
调用点实例化出来的模板函数
bool compare<int>(int a, int b)
{
	return a > b;
}

bool compare<double>(double a, double b)
{
	return a > b;
}
*/

int main()
{
	// 函数的调用点
	compare<int>(10, 20);
	compare<double>(10.5, 20.5);

	// 函数模板实参推演
	compare(20, 20); 	 // 还是用的刚才实例化的compare<int>
	// compare(30, 40.5); // 错误,推演不出来是什么类型
	// 解决方法一:template<typename T, typename E>,a和b用两个类型,各推各的
	// 解决方法二:compare<int>(30, 40.5),double强转成int
}

函数模板:不进行编译,因为类型还不知道
模板函数 :在函数调用点,编译器用程序员指定的类型,从原模板实例化一份函数代码出来这就叫做模板函数,这是实例化出来真正需要进行编译的函数 ,因此站在编译器的角度来看,待编译的函数并没有减少,只是我们编写的代码量减少了。

同时,实例化出来的模板函数在.o文件符号表中产生相应的符号,每个函数名的符号只能出现一次

来看看字符串的情况 (模板的特例化)

cpp 复制代码
// 针对compare函数模板,提供const char*类型的特例化版本
template<>	// 要写上
bool compare(const char* a, const char* b)
{
	cout << "compare<const char*>" << endl;
	return strcmp(a, b) > 0;
}
// 模板特化不需要在函数名后面加上类型参数
// 即别写成compare<const char*>

int main()
{
	// 推演T为const char*,字符串 > 代表的是比较两个常量的地址,要用strcmp才能比较字符串的字典顺序
	// 对于某些类型来说,依赖编译器默认实例化的模板代码,代码处理逻辑是错误的
	// 这时候,就需要我们进行模板的特例化了,这不是编译器提供的,而是程序员提供的
	compare("aaa", "bbb");
	compare<const char*>("aaa", "bbb");
	// 这两种写法都是对的
}

当然,非模板函数(普通函数)优先被调用

cpp 复制代码
//非模板函数 - 普通函数
bool compare(const char* a, const char* b)
{
	cout << "normal compare" << endl;
	return strcmp(a, b) > 0;
}

int main()
{
	// 这时候就调用普通函数了,不调用模板函数了
	compare("aaa", "bbb");
	// 调用模板函数
	compare<const char*>("aaa", "bbb");
}

编译器优先把compare处理成函数名字,没有的话,才去找compare模板特例化,如果没有特例化,才进行模板的实例化

分文件编写

模板代码是不能在一个文件中定义,在另一个文件中使用的,否则链接的时候会出现错误

比如在test.cpp中存放模板代码,在main.cpp中声明,这是不可以的,因为声明产生的符号是*UND*,而在test.cpp中只有模板,模板本身是不编译的,没有模板实例化出来的compare<int>等函数,所以不可以

模板代码调用之前,一定要看到模板定义的地方,这样的话,模板才能进行正常的实例化,产生能够被编译器编译的代码。

所以,模板代码都是放在头文件.h当中的,然后在原文件当中直接进行#include包含

模板的非类型参数:

必须是整数类型(整数或者地址/引用都可以)是常量,只能使用,而不能修改

模板不仅可以接受类型参数typename T,还可以接受非类型参数。这些非类型参数可以是整型、指针、引用等。它们在编译时是常量,只能使用,不能修改

示例代码:

cpp 复制代码
template <int N>
class Array {
public:
    int arr[N];
    
    int size() const { return N; }
};

int main() {
    Array<5> myArray; // 创建一个包含5个整数的数组
    cout << "Array size: " << myArray.size() << endl;
    return 0;
}
cpp 复制代码
// 使用模板实现冒泡排序
template <typename T, int N>
void bubbleSort(T* arr) {
	for (int i = N - 1; i >= 1; --i)
	{
		int flag = 0;
		for (int j = 1; j <= i; ++j)
		{
			if (arr[j - 1] > arr[j])
			{
				T temp = arr[j];
				arr[j] = arr[j - 1];
				arr[j - 1] = temp;
				flag = 1;
			}
		}
		if (flag == 0)
			return;
	}
}

int main() {
	int arr[] = { 64, 34, 25, 12, 22, 11, 90 };
	const int size = sizeof(arr) / sizeof(arr[0]);

	// 调用冒泡排序模板函数
	bubbleSort<int, size>(arr);

	cout << "排序后的数组: ";
	for (int i : arr)
		cout << i << " ";
	cout << endl;

	return 0;
}

二、初识类模板

三、理解容器空间配置器allocator的重要性

四、实现C++STL向量容器vector代码

相关推荐
小芒果_012 分钟前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj8 分钟前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT9 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
-Even-12 分钟前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus
我是谁??1 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
发霉的闲鱼1 小时前
MFC 重写了listControl类(类名为A),并把双击事件的处理函数定义在A中,主窗口如何接收表格是否被双击
c++·mfc
小c君tt1 小时前
MFC中Excel的导入以及使用步骤
c++·excel·mfc
xiaoxiao涛2 小时前
协程6 --- HOOK
c++·协程
羊小猪~~4 小时前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
脉牛杂德4 小时前
多项式加法——C语言
数据结构·c++·算法