C++——模板小结

模板

模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。C++ 的标准库提供许多有用的函数大多结合了模板的观念,如STL以及IO Stream。模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。

模板是一种对类型进行参数化的工具;

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

(一)函数模板

1 template <class 形参名,class 形参名,......> 
2  返回类型 函数名(参数列表)
3 
4    {
5 
6       函数体
7 
8    }

下面我们以一个交换变量的程序来展示函数模板的作用

 1 #include<iostream>
 2 using namespace std;
 3 void Swap(int &a,int &b)
 4 {
 5     int t = a;
 6     a = b;
 7     b = t;
 8 }
 9 int main(int argc, char const *argv[])
10 {
11     int a = 23,b = 45;
12     char c = 'a',d = 'b';
13     Swap(a,b);
14     //Swap(c,d); //报错,因为我们只能交换int类型的两个变量
15     cout<<a<<" "<<b<<endl;
16     return 0;
17 }

这是我们普通的交换变量的程序,但它有局限,我们只能交换一种我们规定好的类型变量,换一种就不能交换了,当然我们也可以用重载的办法,但重载就意味着我们要写出包括所有情况的函数,这样工作量很大,有没有简单一点的办法呢?这时候我们就要用到模板了,用一个函数来实现所有的。

 1 #include<iostream>
 2 using namespace std;
 3 void Swap(int &a,int &b)
 4 {
 5     int t = a;
 6     a = b;
 7     b = t;
 8 }
 9 template<class T>
10 void Swap(T &a,T &b)
11 {
12     T temp = a;
13     a = b;
14     b = temp;
15 }
16 int main(int argc, char const *argv[])
17 {
18     int a = 23,b = 45;
19     char c = 'a',d = 'b';
20     Swap(a,b);
21     cout<<a<<" "<<b<<endl;
22     Swap(c,d);
23     cout<<c<<" "<<d<<endl;
24     return 0;
25 }

看结果,我们可以看到,不仅是int型的,char型的也可以交换,当然我们还可以交换double型的,但大家注意,因为我们前面有写普通的交换函数,所有会默认调用普通的函数,原因是虽然编译器会帮我们做类型转换(T变成int),但能不转的时候编译器不会转,大家可以试试,那如果我们要指定用我们写的模板函数怎么办呢?

1 Swap<>(int a,int b)//这样就会指定调用模板函数
 1 #include<iostream>
 2 using namespace std;
 3 void Swap(int &a,int &b)
 4 {
 5     cout<<"普通函数"<<endl;
 6     int t = a;
 7     a = b;
 8     b = t;
 9 }
10 template<class T>
11 void Swap(T &a,T &b)
12 {
13     cout<<"模板函数"<<endl;
14     T temp = a;
15     a = b;
16     b = temp;
17 }
18 int main(int argc, char const *argv[])
19 {
20     int a = 23,b = 45;
21     char c = 'a',d = 'b';
22     Swap(a,b);
23     cout<<a<<" "<<b<<endl;
24     Swap(c,d);
25     cout<<c<<" "<<d<<endl;
26     return 0;
27 }

看上面的运行结果我们可以发现,编译器调用的是普通函数,当我们指定要调用模板函数时

 1 #include<iostream>
 2 using namespace std;
 3 void Swap(int &a,int &b)
 4 {
 5     cout<<"普通函数"<<endl;
 6     int t = a;
 7     a = b;
 8     b = t;
 9 }
10 template<class T>
11 void Swap(T &a,T &b)
12 {
13     cout<<"模板函数"<<endl;
14     T temp = a;
15     a = b;
16     b = temp;
17 }
18 int main(int argc, char const *argv[])
19 {
20     int a = 23,b = 45;
21     char c = 'a',d = 'b';
22     Swap<>(a,b);
23     cout<<a<<" "<<b<<endl;
24     Swap(c,d);
25     cout<<c<<" "<<d<<endl;
26     return 0;
27 }

我们可以看到,在Swap后面加<>之后就会指定调用模板函数。或者Swap<int>(a,b),这样编译器就不用去进行类型推导了。

(二)类模板

模板类格式如下:

1 template<class  形参名,class 形参名,…>
2     class 类名{ ... };

类模板的话,我们以一个实例来引出:

需求:
写一个各边长度的数组类Array
用于存放各种元素,个数未知
设计:
内部动态申请一个buffer
capacity:表示buffer的大小
size:表示buffer已经存放元素的个数
接口:
Size():
Capacity():最大容量
Clear():清空,使size为0,capacity不变
PushBack():添加一个元素。

问题:这个问题我们首先以double型的为例,代码如下:

 1 #include<iostream>
 2 using namespace std;
 3 #include<string.h>
 4 class Myarry
 5 {
 6 public:
 7     Myarry(int capacity = 5)    //初始的数组内存
 8     {
 9         m_buffer = new double[capacity];  //开辟一个大小为5的内存空间
10         m_size = 0;                      //初始size为0
11         m_capacity = capacity;           //初始的大小为5
12     }
13     int Size()                    //已存元素的个数
14     {
15         return m_size;
16     }
17     int Capacity()               //开辟的内存大小
18     {
19         return m_capacity;
20     }
21     void Clear()                  //清空数组
22     {
23         delete []m_buffer;        //删除数组
24         m_size = 0;               //元素个数清0
25         cout<<"Arrary cleared!"<<endl;
26     }
27     void PushBack(double val)     //添加元素
28     {
29         if(m_size >= m_capacity)  //如果数组已存的元素个数大于开辟的空间,就开辟内存
30         {
31             cout<<"Expand the Memory!"<<endl;
32             m_capacity = m_capacity + 2;   //扩大两个元素的大小
33             double *buffer = new double[m_capacity];  //开辟一个新的空间
34             memcpy(buffer,m_buffer,m_capacity * sizeof(double));  //把旧的数组的元素拷贝一下
35             delete []m_buffer;   //删除旧的数组
36             m_buffer = buffer;    //让数组指针指向新数组
37         }
38         m_buffer[m_size++] = val;   //把val的值添加到数组中,数组已存长度+1
39     }
40 private:
41     double *m_buffer;             //数组指针
42     int m_capacity;              //数组内存大小
43     int m_size;                  //数组已存元素个数
44 };
45 int main(int argc, char const *argv[])
46 {
47     Myarry a;                   //实例化出一个对象
48     cout<<"Capacity:"<<a.Capacity()<<endl;  //输出初始数组的大小和已存元素个数
49     cout<<"Size:"<<a.Size()<<endl;
50     a.PushBack(2.3);     //添加五个元素
51     a.PushBack(1.1);
52     a.PushBack(3.4);
53     a.PushBack(2.1);
54     a.PushBack(3.7);
55     cout<<"Capacity:"<<a.Capacity()<<endl;  //输出现在数组的大小和已存元素个数
56     cout<<"Size:"<<a.Size()<<endl;
57     a.PushBack(4.5);              //再添加一个元素,此时已经大于数组的内存大小,需要扩增内存
58     cout<<"Capacity:"<<a.Capacity()<<endl;  //输出现在数组的大小和已存元素个数
59     cout<<"Size:"<<a.Size()<<endl;
60     a.Clear();    //清空数组
61     cout<<"Capacity:"<<a.Capacity()<<endl;  //输出现在数组的大小和已存元素个数
62     cout<<"Size:"<<a.Size()<<endl;
63     return 0;
64 }

 上面是我们用普通的类实现,但需求是要实现各种类型的,那我们怎么解决呢?这时候就要用到模板类了。

 1 #include<iostream>
 2 using namespace std;
 3 #include<string.h>
 4 template <class T>
 5 class Myarry
 6 {
 7 public:
 8     Myarry(int capacity = 5)    //初始的数组内存
 9     {
10         m_buffer = new T[capacity];  //开辟一个大小为5的内存空间
11         m_size = 0;                      //初始size为0
12         m_capacity = capacity;           //初始的大小为5
13     }
14     int Size()                    //已存元素的个数
15     {
16         return m_size;
17     }
18     int Capacity()               //开辟的内存大小
19     {
20         return m_capacity;
21     }
22     void Clear()                  //清空数组
23     {
24         delete []m_buffer;        //删除数组
25         m_size = 0;               //元素个数清0
26         cout<<"Arrary cleared!"<<endl;
27     }
28     void PushBack(T val)     //添加元素
29     {
30         if(m_size >= m_capacity)  //如果数组已存的元素个数大于开辟的空间,就开辟内存
31         {
32             cout<<"Expand the Memory!"<<endl;
33             m_capacity = m_capacity + 2;   //扩大两个元素的大小
34             T *buffer = new T[m_capacity];  //开辟一个新的空间
35             memcpy(buffer,m_buffer,m_capacity * sizeof(T));  //把旧的数组的元素拷贝一下
36             delete []m_buffer;   //删除旧的数组
37             m_buffer = buffer;    //让数组指针指向新数组
38         }
39         m_buffer[m_size++] = val;   //把val的值添加到数组中,数组已存长度+1
40     }
41     void printf()                  //输出数组中的元素
42     {
43         T  *ptr = m_buffer;       //定义一个T类型的指针和下面的变量n,用来遍历数组
44         int n = m_size;           
45         for(int i = 0; i < n;i++)
46         {
47             cout<<ptr[i]<<" ";
48         }
49         cout<<endl;
50     }
51 private:
52     T *m_buffer;             //数组指针
53     int m_capacity;              //数组内存大小
54     int m_size;                  //数组已存元素个数
55 };
56 int main(int argc, char const *argv[])
57 {
58     Myarry<char> b;
59     b.PushBack('a');     //添加五个元素
60     b.PushBack('b');
61     b.PushBack('z');
62     b.PushBack('j');
63     b.PushBack('f');
64     cout<<"Capacity:"<<b.Capacity()<<endl;
65     cout<<"Size:"<<b.Size()<<endl;
66     b.PushBack('z');
67     b.printf();
68     b.Clear();
69     cout<<"Capacity:"<<b.Capacity()<<endl;
70     cout<<"Size:"<<b.Size()<<endl;
71     return 0;
72 }

原文地址:https://www.cnblogs.com/953-zjf/p/template.html