zoukankan      html  css  js  c++  java
  • C++中的模板那点事

    1.什么是模板

    假设现在我们完成这样的函数,给定两个数x和y求式子x^2 + y^2 + x * y的值 .考虑到x和y可能是 int , float 或者double类型,那么我们就要完成三个函数:

    int fun(int x,int y);

    float fun(float x,float y);

    double fun(double x,double y);

    并且每个fun函数内部所要完成的操作也是极其的相似。如下:

    View Code
     1 int fun(int x,int y)
     2 {
     3     int tmp = x *x + y * y + x * y;
     4     return tmp;
     5 }
     6 float fun(float x,float y)
     7 {
     8     float tmp = x *x + y * y + x * y;
     9     return tmp;
    10 }
    11 double fun(double x,double y)
    12 {
    13     double tmp = x *x + y * y + x * y;
    14     return tmp;
    15 }

    可以看出,上面的三个函数体除了类型不一样之外,其他的完全一样,那么如果能够只写一个函数就能完成上面的三个函数的功能该多好呢?如果从这三个函数提炼出一个通用函数,而它又适用于这三种不同类型的数据,这样会使代码的重用率大大提高。实际上C++中的模板正好就是来解决这个问题的。模板可以实现类型的参数化(把类型定义为参数),从而实现了真正的代码可重用性。C++中的模板可分为函数模板和类模板,而把函数模板的具体化称为模板函数,把类模板的具体化成为模板类。下面让我们分别看看什么是函数模板和类模板吧~~~

    2.模板函数

    实际上我们利用函数模板,只需要一个函数就可能完成上面的三个函数了,千言万语不如看代码: 

    View Code
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 template <typename T>
     6 T fun(T x,T y)
     7 {
     8     T tmp = x *x + y * y + x * y;
     9     return tmp;
    10 }
    11 int main()
    12 {
    13     int x1 = 1,y1 = 4;
    14     float x2 = 1.1 , y2 = 2.2;
    15     double x3 = 2.0 , y3 = 3.1;
    16     cout<<fun(x1,y1)<<endl;
    17     cout<<fun(x2,y2)<<endl;
    18     cout<<fun(x3,y3)<<endl;
    19     return 0;
    20 }

    运行结果:

    如此利用模板,我们很轻而易举的达到了我们的目的,而这也大大的提高了代码的可重用性,这也让我们想起了STL中的那些算法了吧,这些算法使用多种的数据类型。实际上STL即使模板的重要应用了。

    现在我们想,如果上面的代码这样调用fun(x1,y2)会怎么样呢?点击编译会出现这样的错误:

    可以看到编译编译出现问题的是fun(x1,y2),说的意思就是没有对应的函数,要么x1和y2都是int型,要么x1和y2都是float型。那么我为什么要说一下这样一种情况呢?主要是为了引出模板也可以同时使用两个:

    View Code
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 
     6 template <typename T1 , typename T2>
     7 T2 fun(T1 x,T2 y)
     8 {
     9     T2 tmp = x *x + y * y + x * y;
    10     return tmp;
    11 }
    12 int main()
    13 {
    14     int x1 = 1,y1 = 4;
    15     float x2 = 1.1 , y2 = 2.2;
    16     double x3 = 2.0 , y3 = 3.1;
    17     cout<<fun(x1,y1)<<endl;
    18     cout<<fun(x2,y2)<<endl;
    19     cout<<fun(x3,y3)<<endl;
    20     cout<<fun(x1,y2)<<endl;
    21     return 0;
    22 }

    运行结果:

    当使用两个模板时,为什么fun(x1,y1)也能正确运行呢?因为当进行这个调用时,T1 = int ,T2 = int。所以这种调用也是没有问题的。

    提到函数想到重载是很自然的吧,那么模板函数能不能重载呢?显然是能的了,还是看代码:

    View Code
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 
     6 template <typename T1 , typename T2>
     7 T2 fun(T1 x,T2 y)
     8 {
     9     cout<<"调用了两个个参数的 fun 函数 ^^ "<<endl;
    10     T2 tmp = x *x + y * y + x * y;
    11     return tmp;
    12 }
    13 template <typename T>
    14 T fun(T x , T y , T z)
    15 {
    16     cout<<"调用了三个参数的 fun 函数 ^^ "<<endl;
    17     T tmp = x * x + y * y + z * z + x * y * z; 
    18     return tmp;
    19 }
    20 int main()
    21 {
    22     int x1 = 1 , y1 = 4 , z1 = 5;
    23     float x2 = 1.1 , y2 = 2.2;
    24     double x3 = 2.0 , y3 = 3.1;
    25     cout<<fun(x1,y1)<<endl;
    26     cout<<fun(x2,y2)<<endl;
    27     cout<<fun(x3,y3)<<endl;
    28     cout<<fun(x1,y2)<<endl;
    29     cout<<fun(x1,y1,z1)<<endl;
    30     return 0;
    31 }

    运行结果:

    从结果已经能看出来模版函数的重载是没有任何问题的了。那么模板函数和非模板函数之间是否能够重载呢??

    View Code
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 template <typename T>
     6 T fun(T x,T y)
     7 {
     8     cout<<"调用了模板函数 ^^ "<<endl;
     9     T tmp = x * x + y * y + x * y;
    10     return tmp;
    11 }
    12 int fun(int x,int y)
    13 {
    14     cout<<"调用了非模板函数 ^^ "<<endl;
    15     int tmp = x * x + y * y + x * y;
    16     return tmp;
    17 }
    18 
    19 int main()
    20 {
    21     int x1 = 1 , y1 = 4;
    22     float x2 = 1.1 , y2 = 2.2;
    23     cout<<fun(x1,y1)<<endl;
    24     cout<<fun(x2,y2)<<endl;
    25     return 0;
    26 }

    运行结果:

    看以看出模版函数和非模板函数也是可能重载的,那么重载函数的调用顺序是怎么样的呢?实际上是先查找非模板函数,要有严格匹配的非模板函数,就调用非模板函数,找不到适合的非模板函数在和模板函数进行匹配。

    到这里,关于模板就说这些吧~~~~

    3.模板类

    要是理解了模版函数,模板类就相当的简单了,只不过模版函数是对函数中的类型使用模板,而模板类是对类中的类型使用模板,这我就不多说了,下面的代码是我以前利用模板写的单链表,这个是模板的典型应用:(测试过)

    View Code
      1 #include <stdio.h>
      2 #include <iostream.h>
      3 
      4 template <class T>
      5 struct SLNode
      6 {
      7     T data;
      8     SLNode<T> *next;
      9     SLNode(SLNode<T> *nextNode=NULL)
     10     {
     11         next = nextNode;
     12     }
     13     SLNode(const T &item,SLNode<T> *nextNode=NULL)
     14     {
     15         data = item;
     16         next = nextNode;
     17     }
     18 };
     19 
     20 template <class T>
     21 class SLList
     22 {
     23 private:
     24     SLNode<T> *head;
     25     SLNode<T> *tail;
     26     SLNode<T> *currptr;
     27     int size;
     28 public:
     29     SLList();
     30     SLList(const T &item);
     31     ~SLList();
     32     bool IsEmpty()const;
     33     int Length()const;
     34     bool Find(int k,T &item)const;
     35     int Search(const T &item)const;
     36     void InsertFromHead(const T &item);
     37     void InsertFromTail(const T &item);
     38     bool DeleteFromHead(T &item);
     39     bool DeleteFromTail(T &item);
     40     void Insert(int k,const T &item);
     41     void Delete(int k,T &item);
     42     void ShowListMember();
     43 };
     44 //构造函数
     45 template <class T>
     46 SLList<T>::SLList()
     47 {
     48     head = tail = currptr = new SLNode<T>();
     49     size = 0;
     50 }
     51 //构造函数
     52 template <class T>
     53 SLList<T>::SLList(const T &item)
     54 {
     55     tail = currptr = new SLNode<T>(item);
     56     head = new SLNode<T>(currptr);
     57     size = 1;
     58 }
     59 //析构函数
     60 template <class T>
     61 SLList<T>::~SLList()
     62 {
     63      SLNode<T> *temp;
     64     while(!IsEmpty())
     65     {
     66         temp = head->next;
     67         head->next = temp->next;
     68         delete temp;
     69         
     70     }
     71 }
     72 //判断链表是否为空
     73 template <class T>
     74 bool SLList<T>::IsEmpty()const
     75 {
     76     return head->next == NULL;
     77 }
     78 //返回链表的长度
     79 template <class T>
     80 int SLList<T>::Length()const
     81 {
     82      return size;
     83 }
     84 //查找第k个节点的阈值
     85 template <class T>
     86 bool SLList<T>::Find(int k,T &item)const
     87 {
     88     if(k < 1)
     89     {
     90         cout<<"illegal position !"<<endl;
     91     }
     92     SLNode<T> *temp = head;
     93     int count = 0;
     94     while(temp != NULL && count < k)
     95     {
     96         temp = temp->next;
     97         count++;
     98     }
     99     if(temp == NULL)
    100     {
    101         cout<<"The list does not contain the K node !"<<endl;
    102         return false;
    103     }
    104     item = temp->data;
    105     return true;
    106 }
    107 //查找data阈值为item是表的第几个元素
    108 template <class T>
    109 int SLList<T>::Search(const T &item)const
    110 {
    111     SLNode<T> *temp = head->next;
    112     int count = 1;
    113     while(temp != NULL && temp->data != item)
    114     {
    115         temp = temp->next;
    116         count++;
    117     }
    118     if(temp == NULL)
    119     {
    120         cout<<"The node does not exist !"<<endl;
    121         return -1;
    122     }
    123     else
    124     {
    125         return count;
    126     }
    127 }
    128 //从表头插入
    129 template <class T>
    130 void SLList<T>::InsertFromHead(const T &item)
    131 {    
    132     if(IsEmpty())
    133     {
    134         head->next = new SLNode<T>(item,head->next);
    135         tail = head->next;
    136     }
    137     else
    138     {
    139         head->next = new SLNode<T>(item,head->next);
    140     }
    141     size++;
    142 }
    143 //从表尾插入
    144 template <class T>
    145 void SLList<T>::InsertFromTail(const T &item)
    146 {
    147     tail->next = new SLNode<T>(item,NULL);
    148     tail = tail->next;
    149     size++;
    150 }
    151 //从表头删除
    152 template <class T>
    153 bool SLList<T>::DeleteFromHead(T &item)
    154 {
    155     if(IsEmpty())
    156     {
    157         cout<<"This is a empty list !"<<endl;
    158         return false;
    159     }
    160     SLNode<T> *temp = head->next;
    161     head->next = temp->next;
    162     size--;
    163     item = temp->data;
    164     if(temp == tail)
    165     {
    166         tail = head;
    167     }
    168     delete temp;
    169     return true;
    170 }
    171 //从表尾删除
    172 template <class T>
    173 bool SLList<T>::DeleteFromTail(T &item)
    174 {
    175     if(IsEmpty())
    176     {
    177         cout<<"This is a empty list !"<<endl;
    178         return false;
    179     }
    180     SLNode<T> *temp = head;
    181     while(temp->next != tail)
    182     {
    183         temp = temp->next;
    184     }
    185     item = tail->data;
    186     tail = temp;
    187     tail->next=NULL;
    188     temp = temp->next;
    189     delete temp;
    190     size--;
    191     return true;
    192 }
    193 //在第k个节点后插入item值
    194 template <class T>
    195 void SLList<T>::Insert(int k,const T &item)
    196 {
    197     if(k < 0 || k > size)
    198     {
    199         cout<<"Insert position Illegal !"<<endl;
    200         return;
    201     }
    202     if(k == 0)
    203     {
    204         InsertFromHead(item);
    205         return;
    206     }
    207     if(k == size)
    208     {
    209         InsertFromTail(item);
    210         return;
    211     }
    212     SLNode<T> *temp = head->next;
    213     int count = 1;
    214     while(count < k)
    215     {
    216         count++;
    217         temp = temp->next;
    218     }
    219     SLNode<T> *p = temp->next;
    220     temp->next = new SLNode<T>(item,p);
    221     size++;
    222 }
    223 //删除第k个节点的值,保存在item中
    224 template <class T>
    225 void SLList<T>::Delete(int k,T &item)
    226 {
    227     if(k <= 0 || k > size)
    228     {
    229         cout<<"Ileegal delete position !"<<endl;
    230         return;
    231     }
    232     if(k == 1)
    233     {
    234         DeleteFromHead(item);
    235         return;
    236     }
    237     if(k == size)
    238     {
    239         DeleteFromTail(item);
    240         return;
    241     }
    242     SLNode<T> *temp = head->next;
    243     int count = 1;
    244     while(count < k-1)
    245     {
    246         count++;
    247         temp = temp->next;
    248     }
    249     SLNode<T> *p = temp->next;
    250     temp->next = p->next;
    251     p->next = NULL;
    252     item = p->data;
    253     delete p;
    254     size--;
    255 }
    256 template <class T>
    257 void SLList<T>::ShowListMember()
    258 {
    259     cout<<"List Member : ";
    260     SLNode<T> *temp = head->next;
    261     while(temp != NULL)
    262     {
    263         cout<<temp->data<<" ";
    264         temp = temp->next;
    265     }
    266     cout<<endl;
    267 }
    268 
    269 /*
    270 1.引入了InsertFronHead,InsertFromTail,DeleteFromHead和DeleteFromTail用来实现
    271   Insert和Delete函数,是一个比较好的方法。
    272 2.SLNode(T &item,SLNode<T> *nextNode)这个构造函数设计的非常巧妙,便于其他成员
    273   函数的实现。
    274 3.插入,删除分为:表头,表尾,中间插入(删除)三种情况
    275 */
    276 
    277 
    278 
    279 int main()
    280 {
    281     int item;
    282     SLList<int> list(12);
    283 
    284     list.Insert(0,11);
    285     cout<<"list number:"<<list.Length()<<endl;
    286     list.ShowListMember();
    287 
    288     list.Insert(2,14);
    289     cout<<"list number:"<<list.Length()<<endl;
    290     list.ShowListMember();
    291 
    292     list.Insert(2,13);
    293     cout<<"list number:"<<list.Length()<<endl;
    294     list.ShowListMember();
    295 
    296     list.Delete(2,item);
    297     cout<<"item = "<<item<<endl;
    298     cout<<"list number:"<<list.Length()<<endl;
    299     list.ShowListMember();
    300 
    301     list.Delete(1,item);
    302     cout<<"item = "<<item<<endl;
    303     cout<<"list number:"<<list.Length()<<endl;
    304     list.ShowListMember();
    305 
    306     list.Delete(2,item);
    307     cout<<"item = "<<item<<endl;
    308     cout<<"list number:"<<list.Length()<<endl;
    309     list.ShowListMember();
    310     return 0;
    311 }

    利用模板的好处是,SLList中的数据可以是任意的数据类型,这也就是泛型编程的概念了吧~~~~


    学习中的一点总结,欢迎拍转哦^^


  • 相关阅读:
    c#写windows服务(转)
    在WebBrowser中通过模拟键盘鼠标操控网页中的文件上传控件(转)
    详细设计说明书
    corethink功能模块探索开发(六)让这个模块在前台显示
    corethink功能模块探索开发(五)开启这个模块的配置
    corethink功能模块探索开发(四)让这个模块跑起来
    corethink功能模块探索开发(三)让这个模块可见
    corethink功能模块探索开发(二)让这个模块可安装
    corethink功能模块探索开发(一)根据已有模块推测目录结构
    PHP中的替代语法(冒号、endif、endwhile、endfor)
  • 原文地址:https://www.cnblogs.com/BeyondAnyTime/p/2636963.html
Copyright © 2011-2022 走看看