<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C++ 模板總結(jié),很全面!

          共 4165字,需瀏覽 9分鐘

           ·

          2022-05-15 00:12

          來自:CSDN,作者:千里修行

          鏈接:https://blog.csdn.net/zhoumin4576/article/details/103602324

          前言:

          大家好,今天給大家分享一篇關(guān)于 c++ 模板總結(jié)概述.
          模板(Template)指 C++ 程序設(shè)計設(shè)計語言中采用類型作為參數(shù)的程序設(shè)計,支持通用程序設(shè)計。C++ 的標準庫提供許多有用的函數(shù)大多結(jié)合了模板的觀念,如 STL 以及 IO Stream。模板是 C++ 支持參數(shù)化多態(tài)的工具,使用模板可以使用戶為類或者函數(shù)聲明一種一般模式,使得類中的某些數(shù)據(jù)成員或者成員函數(shù)的參數(shù)、返回值取得任意類型。
          模板是一種對類型進行參數(shù)化的工具;通常有兩種形式:函數(shù)模板和類模板:
          • 函數(shù)模板 針對僅參數(shù)類型不同的函數(shù);

          • 類模板 針對僅數(shù)據(jù)成員和成員函數(shù)類型不同的類.

          使用模板的目的就是能夠讓程序員編寫與類型無關(guān)的代碼.

          一、函數(shù)模板:

          ?template??
          ?返回類型?函數(shù)名(參數(shù)列表)

          {

          ??????函數(shù)體

          }
          其中 template 和 class 是關(guān)鍵字,class 可以用 typename ?關(guān)鍵字代替,在這里 typename ?和 class 沒區(qū)別,<> 括號中的參數(shù)叫模板形參,模板形參和函數(shù)形參很相像,模板形參不能為空。一但聲明了模板函數(shù)就可以用模板函數(shù)的形參名聲明類中的成員變量和成員函數(shù),即可以在該函數(shù)中使用內(nèi)置類型的地方都可以使用模板形參名。模板形參需要調(diào)用該模板函數(shù)時提供的模板實參來初始化模板形參,一旦編譯器確定了實際的模板實參類型就稱他實例化了函數(shù)模板的一個實例。比如 swap 的模板函數(shù)形式為:
          template??void?swap(T&?a,?T&?b){},
          當調(diào)用這樣的模板函數(shù)時類型T就會被被調(diào)用時的類型所代替,比如? swap(a,b)? 其中 a 和 b 是 int ?型,這時模板函數(shù) swap ?中的形參? T ?就會被 int ?所代替,模板函數(shù)就變?yōu)?swap(int &a, int &b)。而當 swap(c,d) 其中 c 和 d 是 double 類型時,模板函數(shù)會被替換為 swap(double &a, double &b),這樣就實現(xiàn)了函數(shù)的實現(xiàn)與類型無關(guān)的代碼。
          注意:對于函數(shù)模板而言不存在 h(int,int) 這樣的調(diào)用,不能在函數(shù)調(diào)用的參數(shù)中指定模板形參的類型,對函數(shù)模板的調(diào)用應(yīng)使用實參推演來進行,即只能進行 h(2,3)? 這樣的調(diào)用,或者 int a, b; h(a,b)。

          二、類模板:

          類模板的格式為:
          template
          class?類名{?...?};

          類模板和函數(shù)模板都是以 template 開始后接模板形參列表組成,模板形參不能為空,一但聲明了類模板就可以用類模板的形參名聲明類中的成員變量和成員函數(shù),即可以在類中使用內(nèi)置類型的地方都可以使用模板形參名來聲明。比如:
          ??template?class?A
          ??{
          ???????public:?
          ???????T?a;
          ???????T?b;?
          ???????T?hy(T?c,?T?&d);
          ??};

          在類 A 中聲明了兩個類型為T的成員變量 a 和 b,還聲明了一個返回類型為 T 帶兩個參數(shù)類型為 T 的函數(shù) hy。
          類模板對象的創(chuàng)建:比如一個模板類 A,則使用類模板創(chuàng)建對象的方法為 A m ;在類? A 后面跟上一個 <> 尖括號并在里面填上相應(yīng)的類型,這樣的話類 A 中凡是用到模板形參的地方都會被 int 所代替。當類模板有兩個模板形參時創(chuàng)建對象的方法為 A m; 類型之間用逗號隔開。
          對于類模板,模板形參的類型必須在類名后的尖括號中明確指定。比如 A<2> m;用這種方法把模板形參設(shè)置為 int 是錯誤的(編譯錯誤:error C2079: ‘a(chǎn)’ uses undefined class ‘A’),類模板形參不存在實參推演的問題。也就是說不能把整型值 2 推演為 int 型傳遞給模板形參。要把類模板形參調(diào)置為 int ?型必須這樣指定 A m。
          在類模板外部定義成員函數(shù)的方法為:
          template<模板形參列表>?函數(shù)返回類型?類名<模板形參名>::函數(shù)名(參數(shù)列表){函數(shù)體}

          比如有兩個模板形參 T1,T2 的類 A 中含有一個 void h() 函數(shù),則定義該函數(shù)的語法為:
          template?void?A::h(){}。

          注意:當在類外面定義類的成員時 template 后面的模板形參應(yīng)與要定義的類的模板形參一致。模板的聲明或定義只能在全局,命名空間或類范圍內(nèi)進行。即不能在局部范圍,函數(shù)內(nèi)進行,比如不能在 main 函數(shù)中聲明或定義一個模板。

          三、模板的非類型形參:

          • 1、非類型模板形參:模板的非類型形參也就是內(nèi)置類型形參,如 template class B{} ; 其中int a就是非類型的模板形參。

          • 2、 非類型形參在模板定義的內(nèi)部是常量值,也就是說非類型形參在模板的內(nèi)部是常量。

          • 3、非類型模板的形參只能是整型,指針和引用,像 double,String, String ** 這樣的類型是不允許的。但是 double &,double *,對象的引用或指針是正確的。

          • 4、調(diào)用非類型模板形參的實參必須是一個常量表達式,即他必須能在編譯時計算出結(jié)果。

          • 5、注意:任何局部對象,局部變量,局部對象的地址,局部變量的地址都不是一個常量表達式,都不能用作非類型模板形參的實參。全局指針類型,全局變量,全局對象也不是一個常量表達式,不能用作非類型模板形參的實參。

          • 6、全局變量的地址或引用,全局對象的地址或引用 const 類型變量是常量表達式,可以用作非類型模板形參的實參。

          • 7、sizeof 表達式的結(jié)果是一個常量表達式,也能用作非類型模板形參的實參。

          • 8、當模板的形參是整型時調(diào)用該模板時的實參必須是整型的,且在編譯期間是常量,比如 template class A{}; 如果有 int b,這時 A m;將出錯,因為 b 不是常量,如果 const int b,這時 A m; 就是正確的,因為這時 b 是常量。

          • 9、非類型形參一般不應(yīng)用于函數(shù)模板中,比如有函數(shù)模板 template void h(T b){} ,若使用 h(2) 調(diào)用會出現(xiàn)無法為非類型形參 a 推演出參數(shù)的錯誤,對這種模板函數(shù)可以用顯示模板實參來解決,如用 h(2) 這樣就把非類型形參 a 設(shè)置為整數(shù) 3。顯示模板實參在后面介紹。

          • 10、非類型模板形參的形參和實參間所允許的轉(zhuǎn)換:

            • 允許從數(shù)組到指針,從函數(shù)到指針的轉(zhuǎn)換。如:template class A{}; int b[1]; A m;即數(shù)組到指針的轉(zhuǎn)換

            • const 修飾符的轉(zhuǎn)換。如:template class A{}; int b; A<&b> m; 即從 int * 到 const int * 的轉(zhuǎn)換。

            • 提升轉(zhuǎn)換。如:template class A{}; const short b=2; A m; 即從 short 到 int 的提升轉(zhuǎn)換

            • 整值轉(zhuǎn)換。如:template class A{}; A<3> m; 即從 int ?到 unsigned int 的轉(zhuǎn)換。

            • 常規(guī)轉(zhuǎn)換。

          四、類模板的默認模板類型形參:

          • 1、可以為類模板的類型形參提供默認值,但不能為函數(shù)模板的類型形參提供默認值。函數(shù)模板和類模板都可以為模板的非類型形參提供默認值。

          • 2、類模板的類型形參默認值形式為:template class A{};為第二個模板類型形參T2提供int型的默認值。

          • 3、 類模板類型形參默認值和函數(shù)的默認參數(shù)一樣,如果有多個類型形參則從第一個形參設(shè)定了默認值之后的所有模板形參都要設(shè)定默認值,比如 templateclass A{} ;就是錯誤的,因為 T1 給出了默認值,而T2沒有設(shè)定。

          • 4、 在類模板的外部定義類中的成員時 template 后的形參表應(yīng)省略默認的形參類型。比如 template class A{public: void h();} ; 定義方法為template void A::h(){}。

          五、模板的實例化:

          總結(jié)一下,C++ 只有模板顯式實例化 (explicit instantiation), 隱式實例化 (implicit instantiation) ,特化 (specialization,也譯作具體化,偏特化)。首先考慮如下模板函數(shù)代碼:
          [cpp]?view?plaincopyprint?
          template???
          void?swap(T?&a,?T?&b){??
          ...??
          }??

          1、隱式實例化:

          我們知道,模板函數(shù)不是真正的函數(shù)定義,他只是如其名提供一個模板,模板只有在運行時才會生成相應(yīng)的實例,隱式實例化就是這種情況:
          [cpp]?view?plaincopyprint?
          int?main(){??
          ????....??
          ????swap(a,b);??
          ????....??
          }??

          它會在運行到這里的時候才生成相應(yīng)的實例,很顯然的影響效率 這里順便提一下 swap(a,b) ;中的是可選的,因為編譯器可以根據(jù)函數(shù)參數(shù)類型自動進行判斷,也就是說如果編譯器不不能自動判斷的時候這個就是必要的。

          2、顯式實例化:

          前面已經(jīng)提到隱式實例化可能影響效率,所以需要提高效率的顯式實例化,顯式實例化在編譯期間就會生成實例,方法如下:
          [cpp]?view?plaincopyprint?
          template?void?swap(int?&a,int?&b);??

          這樣就不會影響運行時的效率,但編譯時間隨之增加。

          3、特化:

          這個 swap 可以處理一些基本類型如 long int double ,但是如果想處理用戶自定義的類型就不行了,特化就是為了解決這個問題而出現(xiàn)的:
          [cpp]?view?plaincopyprint?
          template?<>?void?swap(job?a,job?b){...}??

          其中 job 是用戶定義的類型.

          六、模板的特化(具體化)和偏特化:

          • 類模板:
          測試代碼如下:

          #include?
          using?namespace?std;
          template
          class?Test{
          public:
          ????Test(T1?i,T2?j):a(i),b(j){cout<<"模板類"<private:
          ????T1?a;
          ????T2?b;
          };
          template<>???//全特化,由于是全特化,參數(shù)都指定了,參數(shù)列表故為空。
          class?Test{
          public:
          ????Test(int?i,char?j):a(i),b(j){cout<<"全特化"<private:
          ????int?a;
          ????int?b;
          };
          template?//由于只指定了一部分參數(shù),剩下的未指定的需在參數(shù)列表中,否則報錯。
          class?Test{
          public:
          ????Test(char?i,T2?j):a(j),b(j){cout<<"個數(shù)偏特化"<private:
          ????char?a;
          ????T2?b;
          };
          template?//這是范圍上的偏特化
          class?Test{
          public:
          ????Test(T1*?i,T2*?j):a(i),b(j){cout<<"指針偏特化"<private:
          ????T1*?a;
          ????T2*?b;
          };
          template//同理這也是范圍上的偏特化
          class?Test{
          public:
          ????Test(T1?i,T2?j):a(i),b(j){cout<<"const偏特化"<private:
          ????T1?a;
          ????T2?b;
          };
          int?main()
          {
          ????int?a;
          ????Test?t1(0.1,0.2);
          ????Test?t2(1,'A');
          ????Test?t3('A',true);
          ????Test?t4(&a,&a);
          ????Test?t5(1,2);
          ????return?0;
          }

          結(jié)果:


          • 函數(shù)模板:
          #include?
          using?namespace?std;
          //模板函數(shù)
          template
          void?fun(T1?a,T2?b){
          ????cout<<"模板函數(shù)"<}
          //全特化
          template<>
          void?fun(int?a,char?b){
          ????cout<<"全特化"<}
          //函數(shù)不存在偏特化,以下代碼是錯誤的
          /*
          template
          void?fun(char?a,T2?b){
          ????cout<<"偏特化"<}
          */
          int?main()
          {
          ????int?a=0;
          ????char?b='A';
          ????fun(a,a);
          ????fun(a,b);
          ????return?0;
          }

          結(jié)果:


          七、模板類的繼承:

          模板類的繼承包括四種::
          • 1、普通類繼承模板類)

          • 2、(模板類繼承了普通類(非常常見))

          • 3、類模板繼承類模板

          • 4、模板類繼承類模板,即繼承模板參數(shù)給出的基類

          其中,普通類繼承模板類比較簡單,如:
          1?template
          2?class?TBase{
          3?????T?data;
          4?……
          5?};
          6?class?Derived:public?TBase{
          7?……
          8?};

          模板類繼承普通類:
          1?class?TBase{
          2?……
          3?};
          4?template
          5?class?TDerived:public?TBase{
          6?T?data;
          7?……
          8?};

          類模板繼承類模板:
          ?1?template
          ?2?class?TBase{
          ?3?T?data1;
          ?4?……
          ?5?};
          ?6?template
          ?7?class?TDerived:public?TBase{
          ?8?T2?data2;
          ?9?……
          10?};

          模板類繼承模板參數(shù)給出的基類 ——繼承哪個基類由模板參數(shù)決定:
          #include
          using?namespace?std;


          class?BaseA{
          public:
          ????BaseA(){cout<<"BaseA?founed"<};

          class?BaseB{
          public:
          ????BaseB(){cout<<"BaseB?founed"<};

          template
          class?BaseC{
          private:
          ????T?data;
          public:
          ????BaseC():data(rows){
          ????????cout<<"BaseC?founed?"<};

          template
          class?Derived:public?T{
          public:
          ????Derived():T(){cout<<"Derived?founed"<};


          void?main()
          {
          ????Derived?x;//?BaseA作為基類
          ????Derived?y;//?BaseB作為基類
          ????Derived?>?z;?//?BaseC作為基類
          ????
          }

          八、模板實例化問題:

          在我們使用類模板時,只有當代碼中使用了類模板的一個實例的名字,而且上下文環(huán)境要求必須存在類的定義時,這個類模板才被實例化:
          • 1、聲明一個類模板的指針和引用,不會引起類模板的實例化,因為沒有必要知道該類的定義

          • 2、定義一個類類型的對象時需要該類的定義,因此類模板會被實例化

          • 3、在使用 sizeof() 時,它是計算對象的大小,編譯器必須根據(jù)類型將其實例化出來,所以類模板被實例化.

          • 4、 new 表達式要求類模板被實例化。

          • 5、引用類模板的成員會導(dǎo)致類模板被編譯器實例化

          • 6、需要注意的是,類模板的成員函數(shù)本身也是一個模板。標準 C++ 要求這樣的成員函數(shù)只有在被調(diào)用或者取地址的時候,才被實例化。用來實例化成員函數(shù)的類型,就是其成員函數(shù)要調(diào)用的那個類對象的類型。

          --- EOF ---

          瀏覽 37
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲AV无码成人精品区 | 日本亚洲色大成网站www久久 | 亚洲无需播放器 | 影音先锋成人资源AV在线观看 | 毛片AV网址 |