1. 程式人生 > >C++類模版詳解(二)

C++類模版詳解(二)

C++模板

四、類模板的預設模板型別形參

  1、可以為類模板的型別形參提供預設值,但不能為函式模板的型別形參提供預設值。函式模板和類模板都可以為模板的非型別形參提供預設值。

  2、類模板的型別形參預設值形式為:template<class T1, class T2=int> class A{};為第二個模板型別形參T2提供int型的預設值。

  3、類模板型別形參預設值和函式的預設引數一樣,如果有多個型別形參則從第一個形參設定了預設值之後的所有模板形參都要設定預設值,比如template<class T1=int, class T2>class A{};就是錯誤的,因為T1

給出了預設值,而T2沒有設定。

  4、在類模板的外部定義類中的成員時template 後的形參表應省略預設的形參型別。比如template<class  T1, class T2=int> class A{public: void h();}; 定義方法為template<class T1,class T2> void A<T1,T2>::h(){}

定義類模板型別形參:

 演示例項1:

  TemplateDemo.h

複製程式碼
 1 #ifndef TEMPLATE_DEMO_HXX
 2 #define TEMPLATE_DEMO_HXX
 3 
 4 template<class
T> class A{ 5 public: 6 T g(T a,T b); 7 A(); 8 }; 9 10 #endif
複製程式碼

  TemplateDemo.cpp

複製程式碼
 1 #include<iostream.h>
 2 #include "TemplateDemo.h"
 3 
 4 template<class T> A<T>::A(){}
 5 
 6 template<class T> T A<T>::g(T a,T b){
 7     return a+b;
 8
} 9 10 void main(){ 11 A<int> a; 12 cout<<a.g(2,3)<<endl; 13 }
複製程式碼

  執行結果:       5

   類模板的預設模板型別形參示例1:

  TemplateDemo03.h

複製程式碼
 1 #ifndef TEMPLATE_DEMO_03
 2 #define TEMPLATE_DEMO_03
 3 //定義帶預設型別形參的類模板。這裡把T2預設設定為int型。
 4 template<class T1,class T2=int> class CeilDemo{
 5     public:
 6         int ceil(T1,T2);
 7 };
 8 //在類模板的外部定義類中的成員時template 後的形參表應省略預設的形參型別。
 9 template<class T1,class T2> 
10 int CeilDemo<T1,T2>::ceil(T1 a,T2 b){
11     return a>>b;
12 }
13 
14 #endif
複製程式碼

  TemplateDemo03.cpp

複製程式碼
1 #include<iostream.h>
2 #include "TemplateDemo03.h"
3 
4 void main(){
5     CeilDemo<int> cd;
6     cout<<cd.ceil(8,2)<<endl;
7 }
複製程式碼

  執行結果:       2 

  在類模板的外部定義類中的成員時template 後的形參表應省略預設的形參型別,如果沒有省略,不會出現編譯錯誤而是提出警告:
複製程式碼
1 --------------------Configuration: TemplateDemo03 - Win32 Debug--------------------
2 Compiling...
3 TemplateDemo03.cpp
4 g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : 
5 warning C4519: default template arguments are only allowed on a class template; ignored
6 
7 TemplateDemo03.obj - 0 error(s), 1 warning(s)
複製程式碼

  原作者:類模板型別形參預設值和函式的預設引數一樣,如果有多個型別形參則從第一個形參設定了預設值之後的所有模板形參都要設定預設值,比如template<class T1=int, class T2>class A{};就是錯誤的,因為T1給出了預設值,而T2沒有設定。

例項測試如下:

  類模板的預設模板型別形參示例2:

   TemplateDemo03.h

複製程式碼
 1 #ifndef TEMPLATE_DEMO_03
 2 #define TEMPLATE_DEMO_03
 3 
 4 template<class T1=int,class T2,class T3> class CeilDemo{
 5     public:
 6         int ceil(T1,T2,T3);
 7 };
 8 
 9 template<class T1,class T2,class T3> 
10 int CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){
11     return a+b+c;
12 }
13 
14 #endif
複製程式碼

  TemplateDemo03.cpp

複製程式碼
1 #include<iostream.h>
2 #include "TemplateDemo03.h"
3 
4 void main(){
5     CeilDemo<int,int> cd;
6     cout<<cd.ceil(2,3,4)<<endl;
7 }
複製程式碼

  執行結果:        9  

上例中我們看到,雖然多個型別形參則從第一個形參T1設定了預設值為int型別,但後面的兩個並沒有設定預設值。我們在宣告物件的時候指明瞭T2和T3的型別都為int型別,編譯、執行沒有任何警告和錯誤。但並不能否定原作者是錯的,這只是一個特例,看下面的示例:

類模板的預設模板型別形參示例3:

  TemplateDemo03.h

複製程式碼
 1 #ifndef TEMPLATE_DEMO_03
 2 #define TEMPLATE_DEMO_03
 3 
 4 template<class T1=int,class T2,class T3> class CeilDemo{
 5     public:
 6         double ceil(T1,T2,T3);
 7 };
 8 
 9 template<class T1,class T2,class T3> 
10 double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){
11     return a+b+c;
12 }
13 
14 #endif
複製程式碼

  TemplateDemo03.cpp

複製程式碼
1 #include<iostream.h>
2 #include "TemplateDemo03.h"
3 
4 void main(){
5     CeilDemo<double,double> cd;
6     cout<<cd.ceil(2,3.1,4.1)<<endl;
7 }
複製程式碼

  編譯錯誤:

複製程式碼
 1 --------------------Configuration: TemplateDemo03 - Win32 Debug--------------------
 2 Compiling...
 3 TemplateDemo03.cpp
 4 g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : 
 5 error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload
 6 g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : 
 7 error C2065: 'cd' : undeclared identifier
 8 g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : 
 9 error C2228: left of '.ceil' must have class/struct/union type
10 Error executing cl.exe.
11 
12 TemplateDemo03.obj - 3 error(s), 0 warning(s)
複製程式碼

  從上面的例子我們可以看出,當我們試圖把T2和T3定義為double型別就會出現錯誤(T1預設定義的是int型別)。那是不是我們按照作者所說把T2和T3也設定為預設值double,是否還會出現錯誤?看下面的示例:

類模板的預設模板型別形參示例4:

  TemplateDemo03.h

複製程式碼
 1 #ifndef TEMPLATE_DEMO_03
 2 #define TEMPLATE_DEMO_03
 3 
 4 template<class T1=int,class T2=double,class T3=double> class CeilDemo{
 5     public:
 6         double ceil(T1,T2,T3);
 7 };
 8 
 9 template<class T1,class T2,class T3> 
10 double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){
11     return a+b+c;
12 }
13 
14 #endif
複製程式碼

  TemplateDemo03.cpp

複製程式碼
1 #include<iostream.h>
2 #include "TemplateDemo03.h"
3 
4 void main(){
5     CeilDemo<int,double,double> cd;
6     cout<<cd.ceil(2,3.1,4.1)<<endl;
7 }
複製程式碼

  編譯錯誤:

複製程式碼
--------------------Configuration: TemplateDemo03 - Win32 Debug--------------------
Compiling...
TemplateDemo03.cpp
g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : 
error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload
g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : 
error C2065: 'cd' : undeclared identifier
g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : 
error C2228: left of '.ceil' must have class/struct/union type
Error executing cl.exe.

TemplateDemo03.obj - 3 error(s), 0 warning(s)
複製程式碼

  從結果我們可以看出,和上例是一樣的錯誤。從例項中我們可以總結如下:類模板如果有多個型別形參,如果使用型別形參預設值則儘量放在引數列表的末尾,而且預設的引數型別必須相同。如果從第一個形參設定了預設值之後的所有模板形參都要設定和第一個形參同類型的預設值。(宣告:本人也是剛接觸C++,以上只是我經過例項演示對原作者提出的一些質疑,可能我的示例有不到之處,還望大神們不吝賜教,共同完善此部落格,給像我一樣的菜鳥提供一個學習的平臺!)

  接下來驗證不能為函式模板的型別形參提供預設值”

 類模板的預設模板型別形參示例5:

   TemplateDemo04.cpp

複製程式碼
 1 #include<iostream.h>
 2 
 3 template<class T1,class T2,class T3>
 4 T1 sum(T1 a,T2 b,T3 c=int){
 5     return a+b+c;
 6 } 
 7 
 8 void main(){
 9     cout<<sum<double,double>(1.1,2.1,3)<<endl;
10 }
複製程式碼

  編譯錯誤:

複製程式碼
1 --------------------Configuration: TemplateDemo04 - Win32 Debug--------------------
2 Compiling...
3 TemplateDemo04.cpp
4 g:\c++\cdaima\templatedemo04\templatedemo04.cpp(4) : 
5 error C2062: type 'int' unexpected
6 Error executing cl.exe.
7 
8 TemplateDemo04.obj - 1 error(s), 0 warning(s)
複製程式碼

  更改之後的TemplateDemo.cpp

複製程式碼
 1 #include<iostream.h>
 2 
 3 template<class T1,class T2,class T3>
 4 T1 sum(T1 a,T2 b,T3 c){
 5     return a+b+c;
 6 } 
 7 
 8 void main(){
 9     cout<<sum<double,short,int>(1.1,3,257)<<endl;
10 }
複製程式碼

  執行結果:   261.1     

   原作者演示例項如下:

複製程式碼
 1 類模板非型別形參示例
 2 //模板的宣告或定義只能在全域性,名稱空間或類範圍內進行。即不能在區域性範圍,函式內進行,比如不能在main函式中宣告或定義一個模板。
 3 //類模板的定義
 4 template<class T>class A{public:T g(T a, T b); A();};  //定義帶有一個類模板型別形參T的類A
 5 template<class T1,class T2>class B{public:void g();}; //定義帶有兩個類模板型別形參T1,T2的類B
 6 //定義類模板的預設型別形參,預設型別形參不適合於函式模板。
 7 template<class T1,class T2=int> class D{public: voidg();}; //定義帶預設型別形參的類模板。這裡把T2預設設定為int型。
 8 //template<class T1=int, class T2>class E{}; //錯誤,為T1設了預設型別形參則T1後面的所有形參都必須設定認默值。
 9 
10 //以下為非型別形參的定義
11 //非型別形參只能是整型,指標和引用,像double,String, String **這樣的型別是不允許的。但是double &,double *物件的引用或指
12 針是正確的。
13 template<class T1,int a> class Ci{public:void g();}; //定義模板的非型別形參,形參為整型
14 template<class T1,int &a>class Cip{public:void g();}; 
15 template<class T1,A<int>* m> class Cc{public:void g();}; //定義模板的模板型別形參,形參為int型的類A的物件的指標。
16 template<class T1,double*a>class Cd{public:void g();};  //定義模板的非型別形參,形參為double型別的引用。
17 class E{}; template<class T1,E &m> class Ce{}; //非型別模板形參為物件的引用。
18 //以下非型別形參的宣告是錯誤的。
19 //template<class T1,A m>class Cc{}; //錯誤,物件不能做為非型別形參,非型別模板形參的型別只能是物件的引用或指標。
20 //template<class T1,double a>class Cc{}; //錯誤,非型別模板的形參不能是double型別,可以是double的引用。
21 //template<class T1,A<int> m>class Cc{}; //錯誤,非型別模板的形參不能是物件,必須是物件的引用或指標。這條規則對於模板型參
22 也不例外。
23 //在類模板外部定義各種類成員的方法,
24 //typeid(變數名).name()的作用是提取變數名的型別,如int a,則cout<<typeid(a).name()將輸出int
25 template<class T>   A<T>::A(){cout<<"class A goucao"<<typeid(T).name()<<endl;} //在類模板外部定義類的建構函式的方法
26 template<class T> T A<T>::g(T a,T b){cout<<"class A g(T a,T b)"<<endl;} //在類模板外部定義類模板的成員
27 template<class T1,class T2>  voidB<T1,T2>::g(){cout<<"class g f()"<<typeid(T1).name()<<typeid(T2).name()<<endl;}
28 //在類外面定義類的成員時template後面的模板形參應與要定義的類的模板形參一致
29 template<class T1,int a>     voidCi<T1,a>::g(){cout<<"class Ci g()"<<typeid(T1).name()<<endl;}
30 template<class T1,int &a>    voidCip<T1,a>::g(){cout<<"class Cip g()"<<typeid(T1).name()<<endl;} 
31 //在類外部定義類的成員時,template後的模板形參應與要定義的類的模板形參一致
32 template<class T1,A<int> *m> voidCc<T1,m>::g(){cout<<"class Cc g()"<<typeid(T1).name()<<endl;}
33 template<class T1,double* a> voidCd<T1,a>::g(){cout<<"class Cd g()"<<typeid(T1).name()<<endl;}
34 
35 //帶有預設型別形參的模板類,在類的外部定義成員的方法。
36 //在類外部定義類的成員時,template的形參表中預設值應省略
37 template<class T1,class T2>  voidD<T1,T2>::g(){cout<<"class D g()"<<endl;}
38 //template<class T1,class T2=int> void D<T1,T2>::g(){cout<<"class D k()"<<endl;} //錯誤,在類模板外部定義帶有預設型別的形
39 參時,在template的形參表中預設值應省略。
40 //定義一些全域性變數。
41 int e=2;  doubleed=2.2; double*pe=&ed;
42 A<int> mw; A<int> *pec=&mw; E me;
43 
44 //main函式開始
45 int main()
46 { // template<class T>void h(){} //錯誤,模板的宣告或定義只能在全域性,名稱空間或類範圍內進行。即不能在區域性範圍,函式內進行。
47 //A<2> m; //錯誤,對類模板不存在實參推演問題,類模板必須在尖括號中明確指出其型別。
48 //類模板呼叫例項
49 A<int> ma; //輸出"class A goucao int"建立int型的類模板A的物件ma。
50 B<int,int> mb; mb.g(); //輸出"class B g() int int"建立類模板B的物件mb,並把型別形參T1和T2設計為int
51 //非型別形參的呼叫
52 //呼叫非型別模板形參的實參必須是一個常量表達式,即他必須能在編譯時計算出結果。任何區域性物件,區域性變數,區域性物件的地址,區域性
53 變數的地址都不是一個常量表達式,都不能用作非型別模板形參的實參。全域性指標型別,全域性變數,全域性物件也不是一個常量表達式,不能
54 用作非型別模板形參的實參。
55 //全域性變數的地址或引用,全域性物件的地址或引用const型別變數是常量表達式,可以用作非型別模板形參的實參。
56 //呼叫整型int型非型別形參的方法為名為Ci,宣告形式為template<class T1,int a> class Ci
57 Ci<int,3>//正確,數值R是一個int型常量,輸出"class Ci g() int"
58 const int a2=3; Ci<int,a2> mci1; mci1.g(); //正確,因為a2在這裡是const型的常量。輸出"class Ci g() int"
59 //Ci<int,a> mci; //錯誤,int型變數a是區域性變數,不是一個常量表達式。
60 //Ci<int,e> mci; //錯誤,全域性int型變數e也不是一個常量表達式。
61 //呼叫int&型非型別形參的方法類名為Cip,宣告形式為template<class T1,int &a>class Cip
62 Cip<int,e> mcip;  //正確,對全域性變數的引用或地址是常量表達式。
63 //Cip<int,a> mcip1; //錯誤,區域性變數的引用或地址不是常量表達式。
64 //呼叫double*型別的非類形形參類名為Cd,宣告形式為template<class T1,double *a>class Cd
65 Cd<int,&ed> mcd; //正確,全域性變數的引用或地址是常量表達式。
66 //Cd<int,pe> mcd1; //錯誤,全域性變數指標不是常量表達式。
67 //double dd=3.3; //錯誤,區域性變數的地址不是常量表達式,不能用作非型別形參的實參
68 //Cd<int,&e> mcd;  //錯誤,非型別形參雖允許一些轉換,但這個轉換不能實現。
69 
70 //呼叫模板型別形參物件A<int> *的方法類名為Cc,聲名形式為template<class T1,A<int>* m> class Cc
71 Cc<int,&mw> mcc; mcc.g(); //正確,全域性物件的地址或者引用是常量表達式
72 //Cc<int,&ma> mcc;  //錯誤,區域性變數的地址或引用不是常量表達式。
73 //Cc<int,pec> mcc2;  //錯誤,全域性物件的指標不是常量表達式。
74 
75 //呼叫非型別形參E&物件的引用的方法類名為Ce。宣告形式為template<class T1,E &m> class Ce
76 E me1; //Ce<int,me1> mce1; //錯誤,區域性物件不是常量表達式
77 Ce<int,me> mce;  //正確,全域性物件的指標或引用是常量表達式。
78 //非型別形參的轉換示例,類名為Ci
79 //非型別形參允許從陣列到指標,從函式到指標的轉換,const修飾符的轉換,提升轉換,整值轉換,常規轉換。
80 const short s=3; Ci<int,s> mci4†//正確,雖然short型和int不完全匹配,但這裡可以將short型轉換為int型

相關推薦

C++模版()

C++模板 四、類模板的預設模板型別形參   1、可以為類模板的型別形參提供預設值,但不能為函式模板的型別形參提供預設值。函式模板和類模板都可以為模板的非型別形參提供預設值。   2、類模板的型別形參預設值形式為:template<class T1, class

C語言 指標 C語言指標變數的運算

指標變數儲存的是地址,本質上是一個整數,可以進行部分運算,例如加法、減法、比較等,請看下面的程式碼: #include <stdio.h>int main(){ int a = 10, *pa = &a, *paa = &a;

C++

[toc] 超女選秀的例子我們玩了很久,為了學習的需要,暫時離開美眉們,我將採用實際專案開發的例子來講解類的更多知識。 在C語言基礎知識中已學習過檔案操作,在實際開發中,為了提高效率,我會把檔案操作封裝成一個類,類的宣告如下: ```cpp // 檔案操作類宣告 class CFile { privat

c++實戰開發與物件

一、面向物件程式設計介紹 (一)什麼是面向物件?      面向將系統看成通過互動作用來完成特定功能的物件的集合。每個物件用自己的方法來管理資料。也就是說只有物件內部的程式碼能夠操作物件內部的資料。

C# 檔案操作)FileInfo

本篇讓我們一起看一下FileInfo類如何使用。     FileInfo類  提供了與File類相同的功能,不同的是FileInfo提供的都是成員方法   1、讀檔案 1 2 3 4 //摘要:建立只讀 System.IO.FileStrea

C++ 模板():模板的概念和基本使用方式

與函式模板類似地(C++模板詳解(一):函式模板的概念和特性) ,類也可以被一種或多種型別引數化。例如,容器類就是一個具有這種特性的典型例子,它通常被用於管理某種特定型別的元素。只要使用類模板,我們就可以實現容器類,而不需要確定容器中元素的型別。 一、類模板的實現 在這篇博文中,我們使用Stack作為類模板的

[轉]C#進階系列——WebApi 接口返回值不困惑:返回值

try 接口測試工具 des rep home creat port 調用 學習 本文轉自:http://www.cnblogs.com/landeanfen/p/5501487.html 閱讀目錄 一、void無返回值 二、IHttpActionResult

MySQL() 數據庫數據

直接 技術分享 空間 long 需求 mys tex png mms       序言          今天去健身了,感覺把身體練好還是不錯的,閑話不多說,把這個數據庫所遇到的數據類型今天統統在這裏講清楚了,以後在看到什麽數據類型,咱度應該認識,對我來說,最不熟悉的應該就

AppDomain 【轉】-C#中動態加載和卸載DLL

all created 新版本 odin generic reflect 可能 params 詳細 在C++中加載和卸載DLL是一件很容易的事,LoadLibrary和FreeLibrary讓你能夠輕易的在程序中加載DLL,然後在任何地方 卸載。在C#中我們也能使用Asse

Python C API 使用

error 獲取 應該 tro pytho 都是 鍵值 字符 tin 簡介 介紹Python C API中的列表、元組、字典的使用,詳細的進行了API中方法的介紹。 Python List API List API 簡單介紹 int PyList_Check(PyObjec

Java併發(十八):阻塞佇列BlockingQueue BlockingQueue(阻塞佇列)詳解 叉堆(一)之 圖文解析 和 C語言的實現 多執行緒程式設計:阻塞、併發佇列的使用總結 Java併發程式設計:阻塞佇列 java阻塞佇列 BlockingQueue(阻塞佇列)詳解

阻塞佇列(BlockingQueue)是一個支援兩個附加操作的佇列。 這兩個附加的操作是:在佇列為空時,獲取元素的執行緒會等待佇列變為非空。當佇列滿時,儲存元素的執行緒會等待佇列可用。 阻塞佇列常用於生產者和消費者的場景,生產者是往佇列裡新增元素的執行緒,消費者是從佇列裡拿元素的執行緒。阻塞佇列就是生產者

C++學習之路(47)---C++模板與模板深入

1、在c++的Template中很多地方都用到了typename與class這兩個關鍵字,而且有時候二者可以替換,那麼是不是這兩個關鍵字完全一樣呢? 事實上class用於定義類,在模板引入c++後,最初定義模板的方法為:template<class T>,這裡cl

Collection

Collection類之詳解(二) 六、List集合 1.概述 有序的 collection(也稱為序列)。此介面的使用者可以對列表中每個元素的插入位置進行精確地控制。使用者可以根據元素的整數索引(在列表中的位置)訪問元素,並搜尋列表中的元素。 List 介面提供了 4 種對列表元素

C++設計模式 - 代理模式

5.遊戲代練收費 上一篇文章提到了小明請遊戲代練來幫助自己打遊戲升級,但是遊戲代練也不是白幫你玩的,小明需要付費給遊戲代練。 咱們定義一個付費的介面基類。 class ICost { public: ICost(); ~ICost(); virtual

C++11 併發指南六( 型別 std::atomic )

C++11 併發指南六(atomic 型別詳解一 atomic_flag 介紹)  一文介紹了 C++11 中最簡單的原子型別 std::atomic_flag,但是 std::atomic_flag 過於簡單,只提供了 test_and_set 和 clear 兩個 API,不能滿足其他需求(如 s

C++11 併發指南六( 型別 std::atomic )

C++11 併發指南六(atomic 型別詳解一 atomic_flag 介紹)  一文介紹了 C++11 中最簡單的原子型別 std::atomic_flag,但是 std::atomic_flag 過於簡單,只提供了 test_and_set 和 clear 兩個 API,不能滿足其他需求(如 store

C++11 併發指南四( std::packaged_task 介紹)

上一講《C++11 併發指南四(<future> 詳解一 std::promise 介紹)》主要介紹了 <future> 標頭檔案中的 std::promise 類,本文主要介紹 std::packaged_task。 std::packaged_task 包裝一個可呼叫的物件,並且

)java生成隨機數工具RandomUtils

/** * 生成一個隨機的布林值 */ boolean flag = RandomUtils.nextBoolean();

Android Studio 外掛開發:工具

轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/78112856 本文出自【趙彥軍的部落格】 在外掛開發過程中,我們按照開發一個正式的專案來操作,需要整理一些常用工具類。 Http 請求封裝 在外掛的專案中,我們看到依賴庫如下圖所示:

C++11多執行緒(十一):《atomic型別:std::atomic》

參考連結: http://www.cnblogs.com/haippy/p/3301408.html 不錯的部落格 http://www.cplusplus.com/reference/future/future/ cplusplus官網 目錄 1.std::atomic 基本介紹 2.std::atomic