c++模版详解(不涉及编译原理)

server/2025/1/20 16:11:34/

模版的作用

先看看下面的代码感受一下模版的作用吧

#include<iostream>
using namespace std;void Swap(int& a, int& b)
{int temp = a;a = b;b = temp;
}void Swap(double& a, double& b)
{double temp = a;a = b;b = temp;
}int main()
{int a = 1, b = 2;Swap(a, b);cout << "a= " << a << " b= " << b << endl;double c = 1.1, d = 2.2;Swap(c, d);cout << "c= " << c << " d= " << d << endl;return 0;
}

在上面的代码中,我们可以发现Swap函数有2个,而且构成了重载.

这两个Swap函数结构及其相似,有点冗余.

我们开始思考,是否可以只写一个函数来实现交换功能呢?

答案是可以.

我们使用模版就可以轻松缩短代码!

请看:

#include<iostream>
using namespace std;template<class T>
void Swap(T &a, T& b)
{T temp = a;a = b;b = temp;
}int main()
{int a = 1, b = 2;Swap(a, b);cout << "a= " << a << " b= " << b << endl;double c = 1.1, d = 2.2;Swap(c, d);cout << "c= " << c << " d= " << d << endl;return 0;
}

模版的语法

//写法1
template<class T1,class T2>//可以有很多种不同的类型,T3,T4......Tn,但是前面都要加上class修饰//写法2
template<typename T1,typename T2>//typename和class的作用是一样的

template<class + 模版名,class + 模版名2......,class + 模版名n>

class和typename可以混用,但是不推荐.

例子

#include<iostream>
using namespace std;int add(int a, int b)
{return a + b;
}template<class T>
T add(T a, T b)
{return a + b;
}int main()
{int a = 1, b = 2;int c = add(a, b);cout << c << endl;string str1 = "abc";string str2 = "123";string str3 = add(str1, str2);cout << str3 << endl;return 0;
}

这个例子中有两个add函数,c和str3调用的add函数会是同一个吗?

答案是否定的.

调试就会发现:

c调用的是int add

str3调用的是T add

这是为什么呢?

当两个函数都能调用的时候,编译器会优先调用非模版函数.

模版的分类

模版分为函数模版和类模版,我上面举的两个例子都是函数模版,下面我们来看看类模版.

类模板

在c语言,我们可以手搓一个栈(stack),栈的类型是固定的,比如说是int类型的栈.

如果我们想要double类型的栈,就得重写一个或者改写原来的栈.

这样很不方便.

在c++中,我们可以自己写一个有类模版的栈,就不必担心栈的类型了.

在下面的例子中我们有一个类Stack(很简陋,没有完全实现栈的功能),却能定义int和double类型的两个Stack.

#include<iostream>
using namespace std;template<typename T>
class Stack
{public :Stack(size_t capacity = 4){_array = new T[capacity];_capacity = capacity;_size = 0;} void Push(const T& data);
private:T* _array;size_t _capacity;size_t _size;
};template<class T>
void Stack<T>::Push(const T& data)
{// 扩容_array[_size] = data;++_size;
} int main()
{Stack<int> st1; // intStack<double> st2; // doublereturn 0;
}

注意事项:

类模版的声明和定义不能分离,不能在.c头文件声明而在.cpp文件定义,这样会报错!!

哪里使用了模版,就在哪里就实现它.

非类型模版参数

非模版类型参数就是在template里面有未知的模版类型,也有已知的类型

非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用,如下面的例子中的a

template<class T,size_t a = 1>
class test
{
public:T arr[a];
};int main()
{test<string, 10> t;return 0;
}

注意事项:

浮点数、类对象以及字符串是不允许作为非类型模板参数的
 

模版的特化

函数模版的特化

一个模版适用于大部分类型,但也有一些类型无法解决.

如下面的例子:

int类型可以用这个模版,但是string类型不能用

所以针对string类型,我们就要有一个特化

特化的语法

template<>
返回类型 函数名<参数类型>(参数列表) {// 函数体
}

特化的类型

全特化

全特化即是将模板参数列表中所有的参数都确定化。

template<class T1, class T2>
class Data
{public :Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};
template<>
class Data<int, char>
{public :Data() { cout << "Data<int, char>" << endl; }
private:int _d1;char _d2;
};
void TestVector()
{Data<int, int> d1;Data<int, char> d2;
}

偏特化

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。(只有部分参数特化)

template<class T1, class T2>
class Data
{public :Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};// 将第二个参数特化为int
template <class T1>
class Data<T1, int>
{public :Data() { cout << "Data<T1, int>" << endl; }
private:T1 _d1;int _d2;
};

类模版特化

我们将以日期类作为例子,讲解类模版特化 .

下面这篇博客有日期类的具体实现代码,而本篇只提供头文件,让大家大概知道日期类的功能.
C++类和对象(5)——运算符重载(以日期类为例)-CSDN博客

请看下面的代码

template<class T>
struct Less
{bool operator()(const T& x, const T& y) {return x < y;}
};int main()
{Date d1(2025, 1, 19);Date d2(2024, 1, 19);Date d3(2025, 1, 18);vector<Date> v;v.push_back(d1);v.push_back(d2);v.push_back(d3);sort(v.begin(), v.end(),Less<Date>());for (auto& e : v){cout << e << endl;}return 0;
}

这里的Less类里的()重载可以正常运行,但是不适用于下面这种类型

此时需要我们特例化类模版

template<>
struct Less<Date*>
{bool operator()(const Date* x, const Date* y) {return *x < *y;}
};


http://www.ppmy.cn/server/159929.html

相关文章

PHP基础(上)

一.PHP简介 1.什么是PHP 介绍&#xff1a;PHP 全称为 “PHP: Hypertext Preprocessor”&#xff0c;是开源且广泛应用的通用脚本语言。它专为 Web 开发打造&#xff0c;能无缝嵌入 HTML 代码。PHP 支持面向过程与面向对象等多种编程范式&#xff0c;拥有庞大丰富的函数库&…

登录、注册、忘记密码、首页HTML模板

<!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>登录</title><style>body {display: fl…

echarts没有自适应需要调用resize

echarts没有自适应&#xff0c;需要用resize去解决&#xff0c;如下 <template><div class"MonitoringSensor"><div id"main" :style"{ width: width px, height: width px }"></div><button click"change&q…

参数校验 Spring Validation框架

后端参数校验 解决&#xff1a;校验前端传入的参数是否符合预期 1、引入依赖 使用Spring Validation框架 <!-- validation参数校验框架--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validatio…

深度学习项目--基于LSTM的火灾预测研究(pytorch实现)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 LSTM模型一直是一个很经典的模型&#xff0c;这个模型当然也很复杂&#xff0c;一般需要先学习RNN、GRU模型之后再学&#xff0c;GRU、LSTM的模型讲解将…

从 JIRA 数据到可视化洞察:使用 Python 创建自定义图表

引言 在项目管理和软件开发中&#xff0c;JIRA 是最广泛使用的工具之一&#xff0c;尤其是在追踪问题、任务和团队进度方面。对于开发者和团队来说&#xff0c;能够从 JIRA 中提取并分析数据&#xff0c;以便更好地理解项目状态和趋势&#xff0c;至关重要。虽然 JIRA 本身提供…

使用docker部署tomcat服务器和mysql数据库

使用docker部署tomcat服务器 1、拉去tomcat镜像 [rootlocalhost yum.repos.d]# sudo docker pull docker.io/tomcat:9 9: Pulling from library/tomcat de44b265507a: Pull complete 4c2afd91a87d: Pull complete 89e9bbcfa697: Pull complete 11be3e613582: Pull complet…

网络安全 | 什么是正向代理和反向代理?

关注&#xff1a;CodingTechWork 引言 在现代网络架构中&#xff0c;代理服务器扮演着重要的角色。它们在客户端和服务器之间充当中介&#xff0c;帮助管理、保护和优化数据流。根据代理的工作方向和用途&#xff0c;代理服务器可分为正向代理和反向代理。本文将深入探讨这两种…