C++学习笔记三 —— 模板template

250 阅读1分钟

简介

C++中的模板和Java中的泛型一样,是支持参数化多态的工具。

通常有两种形式:函数模板和类模板

函数模板

template <class/typename 形参名,class/typename 形参名,......> 返回类型 函数名(参数列表)
{
    函数体
}

例:

#include <iostream>
#include <string>
using namespace std;

template <typename T>
void swap_num(T &a, T &b)
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}
int main()
{

    int i = 10;
    int j = 20;
    cout << "i: " << i << ", j: " << j << endl;
    swap_num(i, j);
    cout << "i: " << i << ", j: " << j << endl;

    string a = "a";
    string b = "b";
    cout << "a: " << a << ", b: " << b << endl;
    swap_num(a, b);
    cout << "a: " << a << ", b: " << b << endl;

    return 0;
}


//输出
i: 10, j: 20
i: 20, j: 10
a: a, b: b
a: b, b: a

可以看到,函数swap_num有更好的通用性,而不用针对不同类型而定义多个swap_num函数。

类模板

类模板的格式为:

template<class/typename  形参名,class/typename 形参名,…>   class 类名
{ ... };

例:

#include <iostream>
#include <string>
using namespace std;

template <class T, class V>
class Map
{
public:
    T key;   //关键字
    V value; //值
    Map(T k, V v)
    {
        key = k;
        value = v;
    };
};
int main()
{

    Map<int, string> mymap1(1, "A");
    Map<int, string> mymap2(2, "B");
    cout << mymap1.key << "->" << mymap1.value << endl;
    cout << mymap2.key << "->" << mymap2.value << endl;
    return 0;
}

和Java中的定义泛型类还是很相似的。

注意: 模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

不过相比Java,C++模板特别的,有非类型形参的概念。
上例中的class T, class V,这种是叫类型形参,使用时需要传一个类型过去,如Map<int, string>中的int、string。
非类型形参, 如template<class T, int a> class B{}; 其中int a就是非类型的模板形参。
下面写一个通用类型的栈:

#include <iostream>
#include <string>

using namespace std;

template <class T, int MAXSIZE>
class Stack
{ // MAXSIZE由用户创建对象时自行设置
private:
    T elems[MAXSIZE]; // 包含元素的数组
    int numElems;     // 元素的当前总个数
public:
    Stack();              //构造函数
    void push(T const &); //压入元素
    void pop();           //弹出元素
    T top() const;    //返回栈顶元素
    bool empty() const
    { // 返回栈是否为空
        return numElems == 0;
    }
    bool full() const
    { // 返回栈是否已满
        return numElems == MAXSIZE;
    }
};

template <class T, int MAXSIZE>
Stack<T, MAXSIZE>::Stack() : numElems(0) // 初始时栈不含元素
{
}

template <class T, int MAXSIZE>
void Stack<T, MAXSIZE>::push(T const &elem)
{
    if (numElems == MAXSIZE)
    {
        throw out_of_range("Stack<>::push(): stack is full");
    }
    elems[numElems] = elem; // 附加元素
    ++numElems;             // 增加元素的个数
}

template <class T, int MAXSIZE>
void Stack<T, MAXSIZE>::pop()
{
    if (numElems <= 0)
    {
        throw out_of_range("Stack<>::pop(): empty stack");
    }
    --numElems; // 减少元素的个数
}

template <class T,int MAXSIZE>
T Stack<T,MAXSIZE>::top()const{
    if (numElems <= 0) {
        throw out_of_range("Stack<>::top(): empty stack");
    }
    return elems[numElems-1];  // 返回最后一个元素
}

int main()
{
    try
    {
        Stack<int, 20> int20Stack; // 可以存储20个int元素的栈
        int20Stack.push(7);
        cout << int20Stack.top() << endl; // 7
        int20Stack.pop();
        int20Stack.pop();
    }
    catch (exception const &ex)
    {
        cerr << "Exception: " << ex.what() << endl;
        return EXIT_FAILURE;
    }
}


//输出
7
Exception: Stack<>::pop(): empty stack

其中int MAXSIZE就是非类型形参,在使用模板类的时候传入,在模板内部是常量值。
注:非类型形参只能是整型,指针和引用