当前位置: 首页 > news >正文

「C++」初识模板

目录

函数模板

概念:

使用方法:

同名函数与模板函数的选择

类模板

泛型编程

模板原理

模板实例化

 后记


哈喽大家好啊~这里是小鸥的C++频道~

在上一篇我们了解了内存管理在C++中的相关内容,今天我们将简单的来学习一下C++中模板相关的内容。

本期专栏:C++_海盗猫鸥的博客-CSDN博客

个人主页:海盗猫鸥-CSDN博客

欢迎大家关注喔~~~


函数模板

概念:

模板顾名思义,函数模板就是一个与类型无关的代码块,在使用时,编译器将模板中的类型替换为需要的类型,从而使一个模板可以为多种类型的参数使用

使用方法:

template<typename/class 类型名1, typename/class 类型名2, ...>

//函数模板
//关键字:template
//使用方法:template<typename/class 类型名1, typename/class 类型名2, ...>
template<typename T>
void Swap(T& x1, T& x2)
{T tmp = x1;x1 = x2;x2 = tmp;
}
void func1(const T1& x1, const T2& x2)
{cout << x1 << "\t" << x2 << endl;
}//使用函数模板,可以将结构相同,参数类型不同的函数统一化,省去不必要的重复劳动
//这种编程方法,称为范型编程int main()
{int a = 1;int b = 2;Swap(a, b);cout << a << "\t" << b << endl;char c = 'A';char d = 'B';Swap(c, d);cout << c << '\t' << d << endl;func1(1, 2.2);//直接传常值作为参数,又因为func函数参数为引用,所以必须加const,因为临时变量具有常性return 0;
}

typename是用来定义模板参数关键字,也可以使用class

同名函数与模板函数的选择

1. 一个非模板函数可以和一个同名的模板函数同时存在,且模板函数也可以实例化出与该非模板函数相同的函数;

2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数不会从该模板产生出一个实例。如果模板可以产生一个参数具有更好匹配性的函数, 那么将选择模板

3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

//只用于int类型相加
int Add(int x1, int x2)
{return x1 + x2;
}template<class T>
//模板相加函数
T Add(const T& x1, const T& x2)
{return x1 + x2;
}template<class T1,class T2>
T1 Add(const T1& x1, const T2& x2)
{return x1 + x2;
}int main()
{Add(1, 2);//优先选择非模板函数Add<int>(1, 2);//选择模板函数Add(1, 2.0);//选择第二个模板函数return 0;
}

类模板

以栈部分为示例:

template<class T>
class Stack
{
public:Stack(int n = 4):_array(new T[n]),_size(0),_capacity(n){};~Stack(){delete[] _array;_array = nullptr;_size = _capacity = 0;}void Push(const T& x){//检测空间是否足够if (_size == _capacity){T* tmp = new T[_capacity * 2];memcpy(tmp, _array, sizeof(T) * _size);delete[] _array;_array = tmp;_capacity *= 2;}_array[_size++] = x;}//...此处省略~~~
private:T* _array;int _size;int _capacity;
};int main()
{//类模板只能显示实例化Stack<int> st1;st1.Push(1);st1.Push(1);st1.Push(1);Stack<double> st2;st2.Push(1.1);st2.Push(1.1);st2.Push(1.1);return 0;
}

由上述代码可知:

C++中的栈,就可以直接通过一个模板来实现,直接满足不同类型的栈的需求

C++中的扩容需要手动扩容。

注意(错误点):

不改变参数时,添加const是一个好习惯

由上述模板内容我们可以引出一个新的概念:

泛型编程

在不使用模板时,虽然函数重载就可以解决部分如上述如Swap函数那样,需要多个相同功能的函数的相关问题,但终究还是需要多次重复的书写出相同的代码。

重载函数实现Swap的问题:

  1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
  2. 代码的可维护性比较低,一个出错可能所有的重载均出错

而我们使用模板后,就相当于有了一个模板,就像活字印刷术的发明一样,相同的东西不再需要我们重复的书写。

像模板这样通用的代码,我们称为泛型编程: 

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础

模板原理

上述不论函数模板还是类模板,都只是为一个蓝图,就像造房子需要蓝图。但对于模板来说,“造房子”的过程是交给编译器来完成的,不再需要我们动手。

我们只需让编译器知道我们要的“房子”是什么类型的即可~

而要告诉编译器我们需要的类型,则有两种不同的方法:

模板实例化

由于模板只是一个“蓝图”,我们是不能直接使用的,就像类需要实例化为对象使用一样,模板也需要实例化为实际的函数或者类,才能进行进一步的使用。

而模板实例化的方法有两种:

1. 隐式实例化:让编译器根据实参推演模板参数的实际类型

就如上文Swap函数一样,由于Swap函数的参数中带有我们定义的类型T,所以在调用Swap时,编译器就可以自动推导出T的类型,从而实例化出我们需要的类型的函数。

template<class T>
void Swap(T& x1, T& x2)
{T tmp = x1;x1 = x2;x2 = tmp;
}
int main()
{int a = 1;int b = 2;//Swap<int>(a,b)Swap(a, b);char ch1 = 'A';char ch2 = 'B';Swap(ch1, ch2);double d1 = 1.1;double d2 = 2.2;Swap(d1, d2);return 0;
}

2. 显式实例化:在函数名后的<>中指定模板参数的实际类型

在上文类模板中我们就提及,类模板是不能通过第一种方法来进行实例化的,只能进行显示实例化

而显示实例化的方法就是在类或者函数名的后面紧跟一个<类型名>;

template<class T>
class Stack
{
public:Stack(int n = 4):_array(new T[n]),_size(0),_capacity(n){};~Stack(){delete[] _array;_array = nullptr;_size = _capacity = 0;}void Push(const T& x){//检测空间是否足够if (_size == _capacity){T* tmp = new T[_capacity * 2];memcpy(tmp, _array, sizeof(T) * _size);delete[] _array;_array = tmp;_capacity *= 2;}_array[_size++] = x;}//...
private:T* _array;int _size;int _capacity;
};int main()
{//类模板只能显示实例化Stack<int> st1;st1.Push(1);st1.Push(1);st1.Push(1);Stack<double> st2;st2.Push(1.1);st2.Push(1.1);st2.Push(1.1);Stack<int>* pst = new Stack<int>;//类模板只能显示实例化return 0;
}

 后记

那么本篇博客的内容就到这里结束啦~

欢迎大家指出我的错误与不足,我们下篇再见~


http://www.mrgr.cn/news/57045.html

相关文章:

  • 使用IIS搭建PHP环境时遇到404错误怎么办?
  • 【AIGC半月报】AIGC大模型启元:2024.10(下)
  • python 爬虫 入门 :一点小实战(爬取小说)。
  • OptiTrack光学跟踪系统在虚拟制片、运动分析、遥操作中的应用
  • Vue+ECharts+iView实现大数据可视化大屏模板
  • leetcode动态规划(十二)-最后一块石头的重量
  • vue3可组合函数和hook的用法和使用场景区别
  • C4D.python的标签代码,标签名称,常量名互查工具
  • print_hex_dump调试内核,嘎嘎香
  • c++工程,各个模块间的通信机制设计
  • 进程控制:地址空间、fork与进程异常结束
  • Python日志配置
  • 技术总结(十一)
  • Rust中的Sync特征:确保多线程间安全共享数据
  • 几何算法系列:空间实体体积计算公式推导
  • 不同分辨率的大致带宽
  • 树莓集团:人工智能赋能,共创智慧未来
  • sql数据库的命令行操作(DDL修改表)
  • 餐饮点餐系统小程序源码
  • LeetCode-3185 构成整天的下标对数目Ⅱ
  • 利士策分享,给成功抛个媚眼,学习能否成为“丘比特”?
  • 解除123云盘1G下载限制油猴脚本方法
  • 冒泡,选择,插入,快速,归并排序(JavaScript)代码实现
  • 【面试题】什么是SpringBoot以及SpringBoot的优缺点
  • TitanIDE:解锁编程教学新范式
  • 软考科目怎么选?软考科目选哪个好?