• 快速入门C++第六天——函数模板与类模板


    • 该系列文章大部分摘自博主白鳯《C++面向对象程序设计》✍千处细节、万字总结(建议收藏)http://t.csdn.cn/GxZ6U
    • 如有不好的影响请联系删除

    模板的概念

    在程序设计中往往存在这样的现象:两个或多个函数的函数体完全相同,差别仅在与它们的参数类型不同。

    int Max(int x, int y) {
        return x >= y ? x : y;
    }
    
    double Max(double x, double y) {
        return x >= y ? x : y;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    能否为上述这些函数只写出一套代码呢?解决这个问题的一种方式是使用宏定义

    #define Max(x, y)((x >= y) ? x : y)
    
    • 1

    宏定义带来的另一个问题是,可能在不该替换的地方进行了替换,而造成错误。事实上,由于宏定义会造成不少麻烦,所以在C++中不主张使用宏定义。解决以上问题的另一个方法就是使用模板。

    函数模板

    所谓函数模板,实际上是建立一个通用函数,其函数返回类型和形参类型不具体指定,用一个虚拟的类型来代表,这个通用函数就称为函数模板。在调用函数时,系统会根据实参的类型(模板实参)来取代模板中的虚拟类型,从而实现不同函数的功能。

    template 
    返回类型 函数名(模板形参表)
    {
        函数体
    }
    也可以定义为如下形式
    template 
    返回类型 函数名(模板形参表)
    {
        函数体
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    实际上,template是一个声明模板的关键字,它表示声明一个模板。类型参数(通常用C++标识符表示,如T、type等)实际上是一个虚拟的类型名,使用前并未指定它是哪一种具体的类型,但使用函数模板时,必须将类型实例化。类型参数前需加关键字typename或class,typename和class的作用相同,都是表示一个虚拟的类型名(即类型参数)。

    例1:一个与指针有关的函数模板

    #include 
    using namespace std;
    
    template 
    T Max(T *array, int size = 0) {
    	T max = array[0];
    	for (int i = 1	; i < size; i++) {
    		if (array[i] > max) max = array[i];
    	}
    	return max;
    }
    
    int main() {
    	int array_int[] = {783, 78, 234, 34, 90, 1};
    	double array_double[] = {99.02, 21.9, 23.90, 12.89, 1.09, 34.9};
    	int imax = Max(array_int, 6);
    	double dmax = Max(array_double, 6);
    	cout << "整型数组的最大值是:" << imax << endl;
    	cout << "双精度型数组的最大值是:" << dmax << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    例2:函数模板的重载

    #include 
    using namespace std;
    
    template 
    Type Max(Type x, Type y) {
    	return x > y ? x : y;
    }
    
    template 
    Type Max(Type x, Type y, Type z) {
    	Type t = x > y ? x : y;
    	t = t > z ? t : z;
    	return t;
    }
    
    int main() {
    	cout << "33,66中最大值为 " << Max(33, 66) << endl;
    	cout << "33,66,44中最大值为 " << Max(33, 66, 44) << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    注意:

    • 在函数模板中允许使用多个类型参数。但是,应当注意template定义部分的每个类型参数前必须有关键字typename或class。

    • 在template语句与函数模板定义语句之间不允许插入别的语句。

    • 同一般函数一样,函数模板也可以重载。

    • 函数模板与同名的非模板函数可以重载。在这种情况下,调用的顺序是:首先寻找一个参数完全匹配的非模板函数,如果找到了就调用它;若没有找到,则寻找函数模板,将其实例化,产生一个匹配的模板参数,若找到了,就调用它。

    类模板

    所谓类模板,实际上就是建立一个通用类,其数据成员、成员函数的返回类型和形参类型不具体指定,用一个虚拟的类型来代表。使用类模板定义对象时,系统会根据实参的类型来取代类模板中虚拟类型,从而实现不同类的功能。

    template 
    class Three{
    private:
        T x, y, z;
    public:
        Three(T a, T b, T c) {
            x = a; y = b; z = c;
        }
        T sum() {
            return x + y + z;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    上面的例子中,成员函数(其中含有类型参数)是定义在类体内的。但是,类模板中的成员函数也可以在类模板体外定义。此时,若成员函数中有类型参数存在,则C++有一些特殊的规定:

    1. 需要在成员函数定义之前进行模板声明;
    2. 在成员函数名前要加上“类名<类型参数>::”;

    在类模板体外定义的成员函数的一般形式如下:

    template 
    函数类型 类名<类型参数>::成员函数名(形参表)
    {
        ·····
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    例如,上例中成员函数sum()在类外定义时,应该写成

    template
    T Three::sum() {
        return x + y + z;
    }
    
    • 1
    • 2
    • 3
    • 4

    例子:栈类模板的使用

    #include 
    #include 
    using namespace std;
    
    const int size = 10;
    template 
    class Stack{
    private:
    	T stack[size];
    	int top;
    public:
    	void init() {
    		top = 0;
    	}
    	void push(T t);
    	T pop();
    };
    
    template 
    void Stack::push(T t) {
    	if (top == size) {
    		cout << "Stack is full!" << endl;
    		return;
    	}
    	stack[top++] = t;
    }
    
    template 
    T Stack::pop() {
    	if (top == 0) {
    		cout << "Stack is empty!" < st;
    	st.init();
    	st.push("aaa");
    	st.push("bbb");
    	cout << st.pop() << endl;
    	cout << st.pop() << endl;
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
  • 相关阅读:
    个人财务预算系统BudgetBee
    【Java】网络编程,JUnit单元测试,设计模式
    1200*A. Trust Nobody(贪心)
    编写测试报告
    MCE | Hippo 途径与靶向策略
    数据结构day42
    人脸检测几种模型在RK3399上推理速度对比
    【redis】Stream、String 超详细介绍
    FTP服务器配置(虚拟用户)
    用Speedtest-Tracker跟踪上网速度
  • 原文地址:https://blog.csdn.net/weixin_52263256/article/details/126609582