模板初阶(详解)

[复制链接]
发表于 2026-2-8 02:26:50 | 显示全部楼层 |阅读模式
一、泛型编程

为了引出模板,我们来看下面代码,比如要实现差异范例的交换函数,如下:
  1. void Swap(int& a, int& b)
  2. {
  3.         int c = a;
  4.         a = b;
  5.         b = c;
  6. }
  7. void Swap(char& a, char& b)
  8. {
  9.         char c = a;
  10.         a = b;
  11.         b = c;
  12. }
  13. void Swap(double& a, double& b)
  14. {
  15.         double c = a;
  16.         a = b;
  17.         b = c;
  18. }
复制代码
        如许每个范例交换都必要写一个函数重载,此中代码的重复率很高,只有范例差异而逻辑都一样,写起来也非常的繁琐,那我们能不能写一个通用的函数告诉编译器一个模版让编译器根据差异的范例利用该模版来天生代码呢?这就是本章的主题——模板。
泛型编程编写与范例无关的通用代码,是代码复用的一种本事。模板是泛型编程的根本。
模板分为函数模板和类模板,接下来我们分别来详细学习。
二、函数模版

函数模板的格式:
template<typename T1, typename T2 , ... ... ,typename Tn>
返回范例 函数名(参数列表){}
留意:这里typename可以换为calss,但不能换位struct。
代码示例:
  1. template<typename T>
  2. void Swap(T& a, T& b)
  3. {
  4.         T c = a;
  5.         a = b;
  6.         b = c;
  7. }
复制代码
        如许我们写一个模板就可以省了很多代码,还增长可读性。以上并不是一个函数只是一个模板,必要比及利用这个函数的时间编译器会详细的实例化出对应范例的函数,它和写多个函数重载并没有本质区别,只是说这个工作让编译器帮我们做了而已,在服从上并没有提拔。

        必要留意的是如果在这里传两个差异的参数的话会编译报错,由于这里模板参数只有一个,而传入两个差异的范例的实参的时间,编译器并不会帮你逼迫范例转换,由于它并不知道转成谁人范例出了标题它可不背锅。那么我们硬要传两个差异的参数的话,可以表现的逼迫范例转换成两个类似范例,大概调用的时间在函数名背面加<>,尖括号内里加范例名,也就是表现实例化
如下示例:

        这里有人大概会试图去测试Swap模板,结果还是编不外,这是由于不符合引用的语法,我在之前讲过,如下链接:
C++入门根本-CSDN博客
        对于这种情况,我们可以在表面举行逼迫范例转换存入新的变量内里然后再把新的变量代替原来变量做函数参数。 
        函数模板与模板函数的区别:通过这两个词就可以看出来函数模板的主语是模板,模板函数的主语是函数,那么接下来就好明白了,函数模板就是一个模板如刚才我们写的那些都是函数模板,而模板函数是函数模板颠末实例化后天生的函数。
三、类模板

类模板的界说个格式:
template<typename T1, typename T2, ... ... ,typename Tn>
class 类模板名
{}
同样这里typename可以换为calss,但不能换为struct。
        类模板与函数模板的利用有所差异,类模板在利用的时间必须表现实例化,在类模板名背面加<>尖括号内里放入范例名。
留意:类模板不是类而是模板,要颠末实例化后才是类。如下一个Stack类模板的部门:
  1. // 类模版
  2. template<typename T>
  3. class Stack
  4. {
  5. public :
  6.         Stack(size_t capacity = 4)
  7.         {
  8.                 _array = new T[capacity];
  9.                 _capacity = capacity;
  10.                 _size = 0;
  11.         }
  12.         void Push(const T& data);
  13.         //... ...
  14. private:
  15.         T* _array;
  16.         size_t _capacity;
  17.         size_t _size;
  18. };
  19. // 模版不建议声明和定义分离到两个文件.h 和.cpp会出现链接错误
  20. template<class T>
  21. void Stack<T>::Push(const T& data)
  22. {
  23.         // 扩容
  24.         //... ...
  25.         _array[_size] = data;
  26.         ++_size;
  27. }
  28. int main()
  29. {
  30.         Stack<int> st1;
  31.         Stack<double> st2;
  32.         return 0;
  33. }
复制代码
四、模板参数的匹配原则

接下来讲的匹配原则对于类模板和函数模板都是类似的,我们就以函数模板为例。
一个非模板函数是可以和模板函数同名的,而怎么区分编译器会调用谁人呢,如下:
  1. template<typename T>
  2. T Add(T a, T b)
  3. {
  4.         return a + b;
  5. }
  6. int Add(int a, int b)
  7. {
  8.         return a + b;
  9. }
  10. int main()
  11. {
  12.         int a1 = 2, b1 = 4;
  13.         double a2 = 2.5, b2 = 1.5;
  14.         int ret1=Add(a1, b1);
  15.         double ret2=Add(a2, b2);
  16.         return 0;
  17. }
复制代码
        编译器在做调用(不但指函数的调用)的时间有一个特点,有现成的就调现成的,没现成的就调用模板实例化一个。如这里第一个Add调用的好坏模板函数,第二个Add调用的是模板函数。 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表