• [C++](8)模板的初步了解


    泛型编程

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

    为了支持各种类型的两个数据的交换,我们不得不写出多个函数。比如之前写的swap函数:

    void Swap(int& a, int& b)
    {
    	int tmp = a;
    	a = b;
    	b = tmp;
    }
    void Swap(double& a, double& b)
    {
    	double tmp = a;
    	a = b;
    	b = tmp;
    }
    void Swap(char& a, char& b)
    {
    	char tmp = a;
    	a = b;
    	b = tmp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    它们构成函数重载,但是代码复用率低,一旦出现新的类型,就需要用户自己添加相应的函数。代码维护性低,一但发现错误,所有函数都要一起改。

    我们能否只写一个函数模板,需要什么类型的函数直接让编译器自己往里面填好了生成出来呢?

    答案是可以的,我们称这种方法叫泛型编程

    函数模板

    模板是泛型编程的基础,要用到的关键字:template

    函数模板的定义

    template<typename T1, typename T2,......,typename Tn>
    返回值类型 函数名(参数列表)
    {
        
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5

    👆:typename也可以写成class,当前的角度,用这两个关键字没有区别,T模板参数,是我们定义函数模板要用的类型名,可以自己随别取

    例1:

    template<typename T>
    void Swap(T& a, T& b)
    {
    	T tmp = a;
    	a = b;
    	b = tmp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    模板的声明必须带上模板参数:

    //例1的声明:
    template<typename T>
    void Swap(T& a, T& b)
    
    • 1
    • 2
    • 3

    模板不支持声明和定义分离到两个文件。一般是要放到一个文件中,有些地方会把文件命名成xxx.hpp,寓意头文件和定义实现内容合并在一起。

    函数模板的实例化

    调用Swap函数:

    img

    👆:传入不同类型的参数,编译器会按照模板生成不同的函数来调用。

    另外,C++库里面有swap函数,我们以后也不用自己实现了


    函数模板显式实例化

    如果你写得函数模板无法通过传参来推导类型,就必须手动指定:

    调用时在函数模板名后面跟<><>内是我们自己指定的类型。

    template<typename T>
    T* func(int c) //无法通过传参推导T的类型
    {
    	return newT[n];
    }
    int main()
    {
    	int* p1 = func<int>(10);
    	double* p2 = func<double>(10);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    再看下面的例子:

    template<class T>
    T Add(const T& a, const T& b)
    {
    	return a + b;
    }
    int main()
    {
    	int a = 10;
    	double d = 9.8;
    	Add(a, d);//此处报错:没有与参数列表匹配的 函数模板 "Add" 实例
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    👆:传入的两个参数的类型不同,T的类型无法确认,此时也可以手动指定成Add<int>(a, d);Add<double>(a, d);,这样程序就能运行了,传参的时候会进行强制类型转换。

    模板参数的匹配原则

    int Add(int a, int b) //专门处理int类型的函数
    {
    	return a + b;
    }
    
    template<class T> //通用的函数模板
    T Add(const T& a, const T& b)
    {
    	return a + b;
    }
    
    int main()
    {
    	int a = 1, b = 2;
    	Add(a, b);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    传入int类型的数据,会优先调用哪个函数呢?

    通过调试发现,编译器调用的是专门处理int类型的函数,而没有去用模板实例化生成的。

    如果手动指定类型Add<int>(a, b);那么一定是调用函数模板实例化生成的。

    类模板

    类模板的定义

    template<class T1, class T2, ..., class Tn>
    class 类模板名
    {
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    例:

    template<class T>
    class Stack
    {
    public:
    	Stack(int capacity = 0)
    	{
    		_a = new T[capacity];
    		_capacity = capacity;
    		_top = 0;
    	}
    	~Stack()
    	{
    		delete[] _a;
    		_capacity = 0;
    		_top = 0;
    	}
    	//...
    private:
    	T* _a;
    	int _top;
    	int _capacity;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    类模板是实例化

    类不像函数,函数模板可以根据传参去推导要替换的类型,而类模板没有。

    类模板的实例化需要在类模板名后面跟<><>内的是我们自己指定的类型。

    int main()
    {
    	Stack<int> st1;
    	Stack<double> st2;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    模板参数也支持给缺省参数,比如template<class T = char>,这样如果不指定类型就默认是char类型

  • 相关阅读:
    vue 自适应页面高度
    【RuoYi-Vue-Plus】学习笔记 41 - Easy Excel(一)Excel 2003(*.xls)导入流程分析(源码)
    基于JAVA的俄罗斯方块游戏的设计与实现
    Tessent scan&ATPG(9) simulation mismatch(debug向量仿真问题)
    RK3399平台开发系列讲解(PCI/PCI-E)5.54、PCIE INTx中断机制
    卷积神经网络到底是什么,卷积神经网络是一种
    vue微前端qiankun框架学习到项目实战
    数组中 forEach 和 Map 的区别
    Python-类
    权限系统设计学习总结(5)—— 权限系统设计全面总结
  • 原文地址:https://blog.csdn.net/CegghnnoR/article/details/125471285