六. 函数模板和类模板

发布时间 2023-12-04 17:18:44作者: Beasts777

文章参考:

《C++面向对象程序设计》✍千处细节、万字总结(建议收藏)_白鳯的博客-CSDN博客

1. 引入

在编写函数和类时,有时会出现这样的情况,具体实现方式完全一致,但因此参数类型、返回值类型、数据类型等因素的不同,导致不得不写多个函数或者类(因为C++是强类型语言,无法隐式转换,且有些类型本来就无法转换),这样无疑会增加操作难度。那么,如何简单的完成这一任务呢?

define是一个办法,例如:

#define MAX(x,y) ((x>y) ? x : y);

这样就避免了因数据类型不同而重复编写代码。

但是,define可能导致代码在不该替换的地方进行了替换,从而造成错误,因此C++中不主张使用宏定义。

所有一个更好的办法就是使用模板。

2. 函数模板

声明格式:有两种方式:

  •   template <typename 类型参数>
      返回类型 函数名(模板形参表)
      {
          函数体
      }
    
  •   template <class 类型参数>
      返回类型 函数名(模板形参表)
      {
          函数体
      }
    

可以定义多个类型参数:

  •   template <typename 类型参数1, typename 类型参数2,>
      返回类型 函数名(模板形参表)
      {
          函数体
      }
    

EG:

  • 问题:求当前数组中最大的值。

  • 代码:

    #include <iostream>
    using namespace std;
    
    template <typename T>			// template <class T> 也可以
    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;
    }
    

注意:

  • template语句和函数语句中不允许插入别的语句。
  • 在函数模板中允许使用多个类型参数。但是,应当注意template定义部分的每个类型参数前必须有关键字typenameclass
  • 函数模板也可以重载。
  • 函数模板与同名的非模板函数可以重载。在这种情况下,调用的顺序是:
    1. 寻找一个完全匹配的非模板函数。
    2. 如果找不到,再找函数模板。

3. 类模板

建立类模板,主要是因为有时候,类的数据类型、成员函数的返回类型、形参类型不确定,因此使用类模板。语法与函数模板相似。下面是一个案例:

template <typename T>
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;
    }
    T mul();
}
// 如果在类外定义类模板的成员函数,需要加上模板声明,且函数名前要加上"类名<类型参数>::"
template <typename T>
T Three<T>::(){
	return x * y * z;
}

EG:

  • 代码:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int CAPACITY = 10;
    
    template <typename T>
    class Stack{
    private:
        T stack[CAPACITY];      // 这里使用数组,简化初始化操作
        int top;
    public:
        void init();
        void push(T t);
        T pop();
    };
    
    // 必须加上<T>定义,否则无法识别类
    template <typename T>
    void Stack<T>::init(){
        top = 0;
    }
    
    template <typename T>
    void Stack<T>::push(T t){
        if(this->top == CAPACITY){
            cout << "stack is full"<< endl;
            return;
        }
        stack[top++] = t;
    }
    
    template <typename T>
    T Stack<T>::pop(){
        if (top == 0){
            cout << "stack is empty" << endl;
            return 0;
        }
        return stack[--top];
    }
    
    int main(void){
        // 注意:在初始化模板类时需要指定参数类型
        Stack<int> s;
        s.init();
        s.push(3);
        s.push(5);
        cout << s.pop() << endl;
        cout << s.pop() << endl;
        cout << s.pop() << endl;
        return 0;
    }
    
  • 输出:

    5
    3
    stack is empty
    0
    

注意:

  • 只要是模板类的类外声明,在类名后面都必须加上<类型参数>
  • 使用模板类时,要指定该模板类的参数类型。