日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

C++模板详解

發(fā)布時(shí)間:2023/11/27 生活经验 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++模板详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

參考:C++ 模板詳解(一)

?

模板對(duì)類(lèi)型進(jìn)行參數(shù)化的工具;通常有兩種形式:?

  • 函數(shù)模板:僅參數(shù)類(lèi)型不同;
  • 類(lèi)模板: ??僅數(shù)據(jù)成員成員函數(shù)類(lèi)型不同。

目的:讓程序員編寫(xiě)與類(lèi)型無(wú)關(guān)的代碼。

注意:模板的聲明或定義只能在全局、命名空間、類(lèi)范圍內(nèi)進(jìn)行。即不能在局部范圍、函數(shù)內(nèi)進(jìn)行,比如不能在main函數(shù)中聲明或定義一個(gè)模板。

?

一 函數(shù)模板

1 函數(shù)模板的格式:?

template <class 類(lèi)型名1,class 類(lèi)型名2,......> 
返回類(lèi)型 函數(shù)名(參數(shù)列表)
{函數(shù)體
}
  • template、class是關(guān)鍵字,class可以用關(guān)鍵字typename代替,在這里typename和class沒(méi)區(qū)別
  • <>中的參數(shù)叫模板形參不能為空。模板形參用傳入的實(shí)參類(lèi)型來(lái)初始化。
  • 模板形參可以在 返回類(lèi)型、參數(shù)列表、函數(shù)體內(nèi)使用。一旦編譯器確定了模板實(shí)參類(lèi)型,就稱(chēng)他實(shí)例化了函數(shù)模板的一個(gè)實(shí)例。

?

例1:swap函數(shù)的模板:

template <class T> 
void swap(T& a, T& b)   //參數(shù)列表使用模板形參
{
T tmp = a; //函數(shù)體內(nèi)使用模板形參
a = b;
b = tmp; }
  • 當(dāng)調(diào)用這個(gè)函數(shù)模板時(shí),類(lèi)型T就會(huì)被被調(diào)用時(shí)的類(lèi)型所代替
  • 比如swap(a,b),其中abint?型,模板函數(shù)就變?yōu)?/span>swap(int &a, int &b)
  • 而當(dāng)swap(c,d),其中cddouble型時(shí),模板函數(shù)會(huì)被替換為swap(double &a, double &b)。

?

例2:max函數(shù)的模板?

 1 #include<iostream>
 2 
 3 template<typename T>
 4 const T& myMax(const T &a, const T &b)
 5 {
 6   return a > b ? a : b;
 7 }
 8  
 9 int main()
10 {
11   cout << myMax(2.1, 2.2) << endl;         //輸出2.2  模板實(shí)參被隱式推演成double
12   cout << myMax<double>(2.1, 2.2) << endl; //輸出2.2  顯示指定模板參數(shù)。
13   cout << myMax<int>(2.1, 2.2) << endl;    //輸出2    顯示指定的模板參數(shù),會(huì)將參數(shù)轉(zhuǎn)換為int。
14 
15   return 0;
16 }

??

2、注意:

  • 不存在swap(int, int)這樣的調(diào)用! 即不能用類(lèi)型初始化,只能用實(shí)參推演來(lái)進(jìn)行。即根據(jù)2來(lái)推出int型。
  • 即只能進(jìn)行swap(2, 3); ?或者 ?int a, b; swap(a,b); ? 這樣的調(diào)用。

?

二 類(lèi)模板

1 類(lèi)模板的格式為:

template<class 形參名1, class 形參名2, ...>
class 類(lèi)名
{... 
};
  • 與函數(shù)模板一樣,以template開(kāi)始,后接模板形參列表模板形參不能為空
  • 類(lèi)的數(shù)據(jù)成員和函數(shù)成員可以使用模板形參。

?

:一個(gè)類(lèi)模板的例子:

template<class T> 
class A
{
public: T a;               //類(lèi)成員使用模板形參T b; T func(T c, T &d);
};

?

2 類(lèi)模板對(duì)象的創(chuàng)建

  • 方法:A<int> m; ?類(lèi)A中用到模板形參的地方都會(huì)被int?所代替。
  • 兩個(gè)模板形參:A<int, double> m; ?類(lèi)型之間用逗號(hào)隔開(kāi)。

3 類(lèi)模板形參必須指定類(lèi)型而不是實(shí)參:

  • 必須這樣指定 A<int> m;??明確指定類(lèi)型。
  • 不能這樣使用A<2> m;??類(lèi)模板形參不存在實(shí)參推演的問(wèn)題。

4 在類(lèi)模板外部定義成員函數(shù)的方法為

template<模板形參列表> 
函數(shù)返回類(lèi)型 類(lèi)名<模板形參名>::函數(shù)名(參數(shù)列表) 
{函數(shù)體
}

?

:比如模板類(lèi)A,有兩個(gè)模板形參T1,T2,有一個(gè)成員函數(shù) void func(),則外部定義該函數(shù)的語(yǔ)法為:

template<class T1, class T2>   //與類(lèi)一致
void A<T1, T2>::func()      //類(lèi)名也要加上模板參數(shù)列表
{
}

注意:當(dāng)在類(lèi)外面定義類(lèi)的成員時(shí),template后面的模板形參應(yīng)與所定義的類(lèi)的模板形參一致

?

三 模板的形參

包括 類(lèi)型形參、非類(lèi)型形參、默認(rèn)形參。

1 類(lèi)型形參?

類(lèi)型形參由關(guān)鍵字class或typename后接說(shuō)明符構(gòu)成,如

template<class T> 
void func(T a)
{
};
  • 其中?T?就是一個(gè)類(lèi)型形參,名字由用戶(hù)確定。

?

函數(shù)模板,同一個(gè)類(lèi)型形參,必須用相同類(lèi)型的實(shí)參來(lái)初始化,比如

template<class T>
void func(T a, T b)
{
}
  • 調(diào)用?func(2, 3.2);?將編譯出錯(cuò),因?yàn)?/span>模板形參T同時(shí)被指定為int 和?double,不一致,會(huì)出錯(cuò)。

?

類(lèi)模板,其內(nèi)部成員函數(shù),則沒(méi)有上述的限制,比如?

template<class T>
class A
{
public:T func(T a, T b);   //或者T func(const T &a, const T &b);  普通引用會(huì)編譯報(bào)錯(cuò)
};
  • 聲明 A<int> a;? 調(diào)用?a.func(2, 3.2);??在編譯時(shí)不會(huì)出錯(cuò)
  • 第二個(gè)實(shí)參3.2類(lèi)型為double,在運(yùn)行時(shí),會(huì)強(qiáng)制類(lèi)型轉(zhuǎn)換3

?

:模板類(lèi)的對(duì)象調(diào)用成員函數(shù):?

 1 #include <iostream>
 2 using namespace std;
 3 
 4 template<class T>
 5 class A
 6 {
 7 public:
 8     A();
 9     T func(T a, T b);
10 };
11 
12 template<class T>     //類(lèi)外定義構(gòu)造函數(shù)
13 A<T>::A()
14 {
15 }
16 
17 template<class T>     //類(lèi)外定義成員函數(shù)
18 T A<T>::func(T a, T b)
19 {
20     return a + b;
21 }
22 
23 int main(int argc, char *argv[])
24 {
25     A<int> ia;                        //模板實(shí)參為int類(lèi)型的對(duì)象
26     cout << ia.func(3, 2.1) << endl;  //輸出5
27 
28     A<double> da;
29     cout << da.func(3, 2.1) << endl;  //輸出5.1
30 
31     return 0;
32 }

??

2 非類(lèi)型形參

也就是內(nèi)置類(lèi)型形參,如

template<class T, int a>   //int a 就是非類(lèi)型形參
class B
{
};

非類(lèi)型形參有幾點(diǎn)要注意的:

  • 在模板定義的內(nèi)部是常量值,也就是說(shuō),上面的a在類(lèi)B內(nèi)部是一個(gè)常量。
  • 形參只能是整型、指針、引用,像double、string、string **是不允許的,但是double &、double *、對(duì)象的引用或指針是正確的。
  • 實(shí)參必須是一個(gè)常量表達(dá)式,即必須能在編譯時(shí)計(jì)算出結(jié)果。注意局部對(duì)象/變量和其地址,全局指針/變量/對(duì)象,都不是常量表達(dá)式;全局變量/對(duì)象地址或引用const類(lèi)型變量sizeof的結(jié)果,都是常量表達(dá)式。
  • 形參是整型時(shí),實(shí)參也必須是整型的,且在編譯期間是常量,比如
template <class T, int a> 
class A
{
};

如果有int b; ?這時(shí)?A<int, b> m;?出錯(cuò),因?yàn)?/span>b不是常量;如果有?const int b; ?這時(shí) A<int, b> m; ?正確,因?yàn)檫@時(shí)b是常量。

  • 非類(lèi)型形參一般不應(yīng)用于函數(shù)模板中,比如有函數(shù)模板
template<class T, int a> 
void func(T b)
{
}

若用func(2)調(diào)用,會(huì)出現(xiàn)無(wú)法為非類(lèi)型形參a推演出參數(shù)的錯(cuò)誤;可以用顯示模板實(shí)參來(lái)解決,如用func<int, 3>(2); 把非類(lèi)型形參a設(shè)置為整數(shù)3。

  • 形參實(shí)參間所允許的轉(zhuǎn)換?
//1 數(shù)組到指針,函數(shù)到指針的轉(zhuǎn)換
template<int *a>
class A { };
int b[10];
A<b> m;      //數(shù)組轉(zhuǎn)換成指針 //2 const修飾符的轉(zhuǎn)換
template<const int *a>
class A { };
int b;
A<&b> m;     //從int*轉(zhuǎn)換成const int *//3 提升轉(zhuǎn)換
template<int a>
class A { };
const short b = 2;
A<b> m;       //short到int提升//4 整數(shù)轉(zhuǎn)換
template<unsigned int a>
class A { };
A<3> m;    //int到unsigned int轉(zhuǎn)換//5 常規(guī)轉(zhuǎn)換

??

由用戶(hù)指定棧的大小,并實(shí)現(xiàn)棧的相關(guān)操作?

  1 #include <iostream> 
  2 #include <string> 
  3 #include <stdexcept>  //std::out_of_range
  4 #include <cstdlib>    //EXIT_FAILURE
  5 using namespace std;
  6 
  7 /*********模板類(lèi),聲明開(kāi)始,一般都是放在頭文件的*********/
  8 
  9 template<class T, int MAXSIZE>
 10 class myStack
 11 {
 12 public:
 13     myStack();
 14     void push(T const &);  //入棧
 15     void pop();            //出棧
 16     T    top() const;      //返回棧頂
 17 
 18     bool empty() const     //判斷是否為空
 19     {
 20         return size == 0;
 21     }
 22 
 23     bool full() const      //判斷棧是否已滿(mǎn)
 24     {
 25         return size == MAXSIZE;
 26     }
 27 
 28 private:
 29     T   elems[MAXSIZE];    //使用數(shù)組存放棧元素,由于非類(lèi)型形參MAXSIZE在類(lèi)內(nèi)是一個(gè)常量,所以可以用來(lái)聲明數(shù)組大小
 30     int size;              //棧已使用空間
 31 };
 32 
 33 /**********模板類(lèi),聲明結(jié)束,定義成員函數(shù)開(kāi)始********/
 34 
 35 template<class T, int MAXSIZE>
 36 myStack<T, MAXSIZE>::myStack(): size(0)      //構(gòu)造函數(shù),初始化為空
 37 {
 38 }
 39 
 40 template<class T, int MAXSIZE>
 41 void myStack<T, MAXSIZE>::push(T const &new_elem)     //入棧
 42 {
 43     if(size == MAXSIZE)
 44     {
 45         throw out_of_range("myStack::push(): stack is full");
 46     }
 47     elems[size++] = new_elem;
 48 }
 49 
 50 template<class T, int MAXSIZE>
 51 void myStack<T, MAXSIZE>::pop()       //棧頂出棧
 52 {
 53     if(size <= 0)
 54     {
 55         throw out_of_range("myStack::pop(): stack is empty");
 56     }
 57     --size;
 58 }
 59 
 60 template<class T, int MAXSIZE>
 61 T myStack<T, MAXSIZE>::top() const    //返回棧頂元素
 62 {
 63     if(size <= 0)
 64     {
 65         throw out_of_range("myStack::top(): stack is empty");
 66     }
 67     return elems[size - 1];
 68 }
 69 
 70 /***********成員函數(shù)定義結(jié)束**********************/
 71 
 72 int main(int argc, char *argv[])
 73 {
 74     try
 75     {
 76         myStack<int,    20>  int20Stack;    //顯示模板實(shí)參
 77         myStack<int,    40>  int40Stack;
 78         myStack<string, 40>  stringStack;
 79 
 80         int20Stack.push(7);
 81         cout << int20Stack.top() << endl;   //輸出7
 82         int20Stack.pop();
 83 
 84         for(int i = 0; i < 40; ++i)
 85             int40Stack.push(i);
 86         cout << int40Stack.top() << endl;   //輸出39
 87         //int40Stack.push(41);              //繼續(xù)添加元素,會(huì)拋出異常,輸出Exception: myStack::push(): stack is full
 88         
 89         stringStack.push("hello");
 90         cout << stringStack.top() << endl;  //輸出hello
 91         stringStack.pop();
 92         //stringStack.pop();                //繼續(xù)出棧,會(huì)拋出異常,輸出Exception: myStack::push(): stack is empty
 93 
 94         return 0;
 95     }
 96     catch(out_of_range const &ex)
 97     {
 98         cerr << "Exception: " << ex.what() << endl;
 99         return EXIT_FAILURE;
100     }
101 }

??

3 默認(rèn)形參

1?類(lèi)模板可以有默認(rèn)值,函數(shù)模板不能有默認(rèn)值。

2 類(lèi)模板,類(lèi)型形參,默認(rèn)值形式為:

template<class T1, class T2 = int>   //為第二個(gè)模板類(lèi)型形參提供int型的默認(rèn)值
class A
{
};

3 類(lèi)模板,類(lèi)型形參,默認(rèn)值和普通函數(shù)的默認(rèn)參數(shù)一樣,如果有多個(gè)類(lèi)型形參,則從第一個(gè)設(shè)定了默認(rèn)值的形參之后,所有模板形參都要設(shè)定默認(rèn)值

template<class T1 = int, class T2>  //錯(cuò)誤!如果T1有默認(rèn)值,T2也必須有
class A
{
};

4 類(lèi)模板,類(lèi)型形參,外部定義類(lèi)的成員函數(shù)。template?后的形參列表應(yīng)省略掉默認(rèn)值。

template<class  T1, class T2 = int> 
class A
{
public: void func();
}; template<class T1,class T2>   //定義方法,省略掉默認(rèn)值
void A<T1,T2>::func()
{
}

?

:有默認(rèn)值的類(lèi)模板

 1 #include <iostream>
 2 using namespace std; 
 3 
 4 template<typename T1, typename T2 = double, int abc = 5>  //第二個(gè)類(lèi)型形參和非類(lèi)型形參有默認(rèn)值
 5 class A
 6 {
 7 public:
 8     void print(T1 a, T2 b);
 9 };
10 
11 template<typename T1, typename T2, int abc>   //類(lèi)外定義時(shí)不能有默認(rèn)值,畢竟類(lèi)的聲明是作為接口給別人看的
12 void A<T1, T2, abc>::print(T1 a, T2 b)
13 {
14     cout << a << ' ' << b << endl;
15     cout << abc << endl;16 }
17 
18 int main(int argc, char *argv[])
19 {
20     A<int> a;
21     a.print(2.2, 2.1);   //輸出 2 2.1 5, 輸出2是因?yàn)橹付閕nt型,進(jìn)行了類(lèi)型轉(zhuǎn)換,輸出5是默認(rèn)值
22 
23     return 0;
24 }

?

轉(zhuǎn)載于:https://www.cnblogs.com/qieerbushejinshikelou/p/3961964.html

總結(jié)

以上是生活随笔為你收集整理的C++模板详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。