zoukankan      html  css  js  c++  java
  • 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 }

  • 相关阅读:
    web api的新玩法
    发送邮件的小功能(.net core 版)
    Docker入门命令备份
    在控制台进行依赖注入(DI in Console)
    .net Core 2.0使用NLog
    .Net Core下使用WCF
    C#枚举最优雅的用法
    Jquery.Ajax的使用方法
    PuTTY+Xming实现X11的ssh转发
    使用XMing+putty运行linux图形界面程序
  • 原文地址:https://www.cnblogs.com/953-zjf/p/template.html
Copyright © 2011-2022 走看看