26.C++- 泛型編程之類模板(詳解)


在上章25.C++- 泛型編程之函數模板(詳解) 學習了后,本章繼續來學習類模板

 

類模板介紹

和函數模板一樣,將泛型思想應用於類.

編譯器對類模板處理方式和函數模板相同,都是進行2次編譯

類模板通常應用於數據結構方面,使得類的實現不在關注數據元素的具體類型,而只關注需要實現的功能

比如: 數組類,鏈表類,Queue類,Stack類等

 

使用方法

  • 通過template關鍵字來聲明,然后通過typename關鍵字來定義模板類型,如下圖所示:

 

 

類模板的使用

  • 定義對象時,必須指定類模板類型,因為編譯器無法推導類型
  • 使用具體類型<Type>來定義對象

如下圖所示:

 

 

初探類模板

寫一個類模板,實現不同類型的加減乘除

#include <iostream>
#include <string>

using namespace std;

template < typename T >
class Operator
{
public:
     T add(T a, T b)
    {
        return a + b;
    }

     T minus(T a, T b)
    {
        return a - b;
    }

     T multiply(T a, T b)
    {
        return a * b;
    }

     T divide(T a, T b)
    {
        return a / b;
    }
};
string operator-(string& l, string& r) //由於string類沒有重載減號操作符,所以我們自定義一個 { return "Minus"; } int main() { Operator<int> op1; //定義對象時,需要指定類模板類型 cout << op1.add(1, 2) << endl; Operator<string> op2; //定義對象時,需要指定類模板類型 cout << op2.add("D.T.", "Software") << endl; cout << op2.minus("D.T", "Software") << endl; return 0; }

運行打印:

3
D.T. Software
Minus

 

類模板的工程應用

  • 類模板必須在.h頭文件中定義
  • 類模板的成員函數不能分開在不同的文件中實現
  • 類模板外部定義的成員函數,和模板函數一樣,還需要加上模板template <typename T>聲明,以及結構體<T>聲明

接下來,我們便修改上面代碼定義的Operator類模板,只需要寫Operator.h文件即可:

#ifndef  _OPERATOR_H
#define _OPERATOR_H

template < typename T >
class Operator
{
public:
    T add(T a, T b);
    T minus(T a, T b);
    T multiply(T a, T b);
    T divide(T a, T b);
};

template < typename T >           //外部定義的成員函數,都需要加上模板聲明
T  Operator<T> :: add(T a, T b)  //同時加上結構體<T>聲明
{
       return a+b;
}

template < typename T >          
T  Operator<T> :: minus(T a, T b)
{
       return a-b;
}
template
< typename T > T Operator<T> :: multiply(T a, T b) { return a*b; } template < typename T > T Operator<T> :: divide(T a, T b) { return a/b; } #endif

 

多參數類模板

類模板可以定義任意多個不同的類型參數,同時還要必須指定每個模板參數

例如:

template < typename T1,typename T2 >
class Operator
{
public:
    void add(T1 a, T2 b);
};

template < typename T1,typename T2 >
void Operator<T1,T2 > :: add(T1 a, T2 b)
{
        cout<<a+b<<endl;
}

int main()
{
    Operator<int,float> op1;                 //定義op1對象時,必須指定類模板類型
    op1.add(2,2.1);                                  //4.1
    return 0;
}

運行打印:

4.1

從結果來看,上面的類模板好像已經實現了add加法運算.但是卻不能支持指針類型.

其實,類模板也可以像函數重載一樣, 類模板通過特化的方式可以實現特殊情況.

 

類模板特化

  • 表示可以存在多個相同的類名,但是模板類型都不一致(和函數重載的參數類似)
  • 特化類型有完全特化部分特化兩種類型
  • 完全特化表示顯示指定類型參數,模板聲明只需寫成template<>,並在類名右側指定參數,比如:
template < typename T1,typename T2 >  //聲明的模板參數個數為2個
class Operator                        //正常的類模板
{
public:
        void add(T1 a, T2 b)
       {
              cout<<a+b<<endl;
       }
};

template <>                           //不需要指定模板類型,因為是完全特化的類模板
class Operator< int , int>           //指定類型參數,必須為2個參數,和正常類模板參數個數一致

{                                               

public:

void add(int a, int b)

{

cout<<a+b<<endl;

}

};

int main()

{

       Operator<int,int> Op1;        //匹配完全特化類模板:class Operator< int,int>

       Operator<int,float> Op2;     //匹配正常的類模板

       return 0;

}
  • 部分特化表示通過特定規則約束類型參數,模板聲明和類似,並在類名右側指定參數,比如:
template < typename T1,typename T2 >           //聲明的模板參數個數為2個
class Operator                                 //正常的類模板
{
public:
        void add(T1 a, T2 b)
       {
              cout<<a+b<<endl;
       }
};

 

template < typename T >          //有指定模板類型以及指定參數,所以是部分特化的類模板             
class Operator< T* ,T*>          //指定類型參數,必須為2個參數,和正常類模板參數個數一致
{
public:
  void add(T* a, T* b)
  {
              cout<<*a+*b<<endl;
  }
};

int main()
{
     Operator<int*,int*> Op1;            //匹配部分特化: class Operator< T* ,T*>
     Operator<int,float> Op2;           //匹配正常的類模板: class Operator     
return 0;
}
  • 編譯時,會根據對象定義的類模板類型,首先去匹配完全特化,再來匹配部分特化,最后匹配正常的類模板.

 

初探類模板特化

#include <iostream>

using namespace std; 

template < typename T1,typename T2 >  
class Operator                                            //正常的類模板
{
public:
        void add(T1 a, T2 b)
       {
              cout<<"add(T1 a, T2 b)"<<endl;
              cout<<a+b<<endl;
       }
};

template < typename T >                              
class Operator<T,T>                                //部分特化的類模板,當兩個參數都一樣,調用這個
{
public:
         void add(T a, T b)
       {
              cout<<"add(T a, T b)"<<endl;
              cout<<a+b<<endl;
       }
};

template < typename T1,typename T2 >  
class Operator<T1*,T2*>                                   //部分特化的類模板,當兩個參數都是指針,調用這個
{
public:
        void add(T1* a, T2* b)
       {
              cout<<"add(T1* a, T2* b)"<<endl;
              cout<<*a+*b<<endl;
       }
};

template < >  
class Operator<void*,void*>                             //完全特化的類模板,當兩個參數都是void*,調用這個
{
public:
        void add(void* a, void* b)
       {
              cout<<"add(void* a, void* b)"<<endl;
              cout<<"add void* Error"<<endl;                 //void*無法進行加法
       }
};

int main()
{
       int *p1 = new int(1);
       float *p2 = new float(1.25);

       Operator<int,float>  Op1;        //匹配正常的類模板:class Operator      
       Op1.add(1,1.5);

       Operator<int,int>  Op2;          //匹配部分特化的類模板:class Operator<T,T>
       Op2.add(1,4);

       Operator<int*,float*>  Op3;      //匹配部分特化的類模板:class Operator<T1*,T2*>      
       Op3.add(p1,p2);

       Operator<void*,void*>  Op4;      //匹配完全特化的類模板:class Operator<void*,void*>
       Op4.add(NULL,NULL);  

       delete p1;
       delete p2;

       return 0;
}

運行打印:

add(T1 a, T2 b)
2.5

add(T a, T b)
5

add(T1* a, T2* b)
2.25

add(void* a, void* b)
add void* Error

 

數值型模板參數

之前,我們學習的模板參數都是帶泛型的(表示不同類型),其實模板參數也可以是數值型參數,如下圖所示:

 

 

 

  • 數值型模板參數必須在編譯時被唯一確定

比如: 變量在運行期間是可變的,所以不能作為模板參數.以及浮點數(不精確),類對象(可變)等等.

 

接下來,我們便通過數值參數的類模板來求 1+2+3+...+N的值

代碼如下所示:

template < int N >
class Sum
{
public:
    static const int VALUE = Sum<N-1>::VALUE + N;              //定義靜態常量並賦值
};
template
< > class Sum < 1 > { public: static const int VALUE = 1; }; int main() { cout << "1 + 2 + 3 + ... + 10 = " << Sum<10>::VALUE << endl; cout << "1 + 2 + 3 + ... + 100 = " << Sum<100>::VALUE << endl; return 0; }

運行打印:

1 + 2 + 3 + ... + 10 = 55
1 + 2 + 3 + ... + 100 = 5050

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM