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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++模板 —— 万字带你了解C++模板(蓝桥杯算法比赛必备知识STL基础)

發布時間:2024/3/13 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++模板 —— 万字带你了解C++模板(蓝桥杯算法比赛必备知识STL基础) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

?

模板的概念

函數模板?

?????????函數模板的作用:

函數模板的語法:

解釋:

示例:

總結:

函數模板注意事項

注意事項:

示例:

總結:

?函數模板案例

案例描述:

示例:

普通函數與函數模板的區別

總結:

普通函數與函數模板的調用規則

調用規則如下:

示例:

模板的局限性(函數模板的第二種實現)

類模板

類模板基礎語法?

語法:

解釋:

示例:

類模板與函數模板的區別

問題引出(一)

問題引出(二)

類模板中成員函數調用時機

添加測試代碼:

總結:

類模板對象做函數參數

類模板與繼承

示例:

類模板成員函數類外實現

類模板與友元


模板的概念

模板就是我們建立的通用的模具,用來提高代碼的復用性。

生活中最經典的就是證件照模板了

?上面模板的特點:

  • 模板不可以直接使用,它只是一個框架(不可能拿一個照片模板交給領導或者老師吧,得有你自己的“信息”)

  • 模板的通用并不是萬能的


函數模板?

  • ?C++的另一種編程思想——泛型編程,利用的主要就是模板
  • C++提供兩種模板機制:函數模板類模板

函數模板的作用:

? ? ? ? 建立一個通用函數,其函數返回值類型和形參類型不具制定,用一個虛擬類型代替。

函數模板的語法:

//template告訴編譯器,要開始寫模板了 //typename或者class都可以 //T是虛擬類型 template<typename T> 函數聲明或定義

解釋:

template --- 聲明創建模板

typename --- 表面其后面的符號是一種數據類型,可以用class代替

T --- 通用的數據類型,名稱可以替換,通常為大寫字母

示例:

//交換整型函數 void swapInt(int &a,int &b){int temp = 0;a = b;b = temp; }//交換浮點型函數 void swapDouble(double &a,double &b){double temp = a;a = b;b = temp; }//利用函數模板提供通用的交換函數 template<tyoename T> void mySwap(T &A,T &b) {T temp = a;a = b;b = temp; }void test01() {int a = 10;int b = 20;//swapInt(a, b);//利用模板實現交換//1、自動類型推導mySwap(a, b);//2、顯示指定類型mySwap<int>(a, b);cout << "a = " << a << endl;cout << "b = " << b << endl;}int main() {test01();system("pause");return 0; }

總結:

  • 函數模板利用關鍵字 template

  • 使用函數模板有兩種方式:自動類型推導、顯示指定類型

  • 模板的目的是為了提高復用性,將類型參數化


函數模板注意事項

注意事項:

  • 自動類型推導,必須推導出一致的數據類型T,才可以使用

  • 模板必須要確定出T的數據類型,才可以使用(函數中沒有用到T的話,就只能自己寫了)

示例:

//利用模板提供通用的交換函數 template<class T> //typename可以替換成class void mySwap(T& a, T& b) {T temp = a;a = b;b = temp; }// 1、自動類型推導,必須推導出一致的數據類型T,才可以使用 void test01() {int a = 10;int b = 20;char c = 'c';mySwap(a, b); // 正確,可以推導出一致的T//mySwap(a, c); // 錯誤,推導不出一致的T類型 }// 2、模板必須要確定出T的數據類型,才可以使用 template<class T> void func() {cout << "func 調用" << endl; }void test02() {//因為函數體中沒有用到T,所以自動類型推導也不知道怎么推導了//func(); //錯誤,模板不能獨立使用,必須確定出T的類型func<int>(); //利用顯示指定類型的方式,給T一個類型,才可以使用該模板 }int main() {test01();test02();system("pause");return 0; }

總結:

  • 使用模板時必須確定出通用數據類型T,并且能夠推導出一致的類型


?函數模板案例

案例描述:

  • 利用函數模板封裝一個排序的函數,可以對不同數據類型數組進行排序

  • 排序規則從大到小,排序算法為選擇排序

  • 分別利用char數組int數組進行測試

示例:

//交換函數模板 template<class T> void mySwap(T& a, T& b) {T temp = a;a = b;b = temp; }//排序算法 template<class T> void mySort(T arr[] , int len) {for (int i = 0; i < len ; i++) {int max = i; //先隨便找一個設為最大值for (int j = i + 1; j < len; j++){if (arr[max] < arr[j])//更新下標max = j;}if (max != i){//交換max和i下標的元素mySwap(arr[max],arr[i]);}} }//提供打印數組模板 template<class T> void printArray(T arr[], int len) {for (int i = 0; i < len; i++){cout << arr[i] << " ";}cout << endl; }void test01() {//測試char數組char charArr[] = "bcfac";int num = sizeof(charArr) / sizeof(char);mySort(charArr, num);printArray(charArr , num); }void test02() {//測試int數組int intArr[] = { 7, 5, 8, 1, 3, 9, 2, 4, 6 };int num = sizeof(intArr) / sizeof(int);mySort(intArr, num);printArray(intArr, num); }int main() {test01();test02();system("pause");return 0; }

如果上面這些程序你都實現了,那么你一定會對模板深有體會,模板大大提高了代碼復用,需要熟練掌握


普通函數與函數模板的區別

普通函數與函數模板區別:

  • 普通函數調用時可以發生自動類型轉換(隱式類型轉換)

  • 函數模板調用時,如果利用自動類型推導,不會發生隱式類型轉換

  • 如果利用顯示指定類型的方式,可以發生隱式類型轉換

//普通函數 int myAdd01(int a, int b) {return a + b; }//函數模板 template<class T> T myAdd02(T a, T b) {return a + b; }//使用函數模板時,如果用自動類型推導,不會發生自動類型轉換,即隱式類型轉換 void test01() {int a = 10;int b = 20;char c = 'c';cout << myAdd01(a, c) << endl; //正確,將char類型的'c'隱式轉換為int類型 'c' 對應 ASCII碼 99//myAdd02(a, c); // 報錯,使用自動類型推導時,不會發生隱式類型轉換myAdd02<int>(a, c); //正確,如果用顯示指定類型,可以發生隱式類型轉換 }int main() {test01();system("pause");return 0; }

總結:

????????建議使用顯示指定類型的方式,調用函數模板,因為可以自己確定通用類型T


普通函數與函數模板的調用規則

調用規則如下:

  • 如果函數模板和普通函數都可以實現,優先調用普通函數

  • 可以通過空模板參數列表來強制調用函數模板

  • 函數模板也可以發生重載

  • 如果函數模板可以產生更好的匹配,優先調用函數模板

  • 簡單來說就是,函數模板里面,同名普通函數(只有聲明也成立,只是會報錯🤣)優先調用,同時函數模板也是可以重載的。

    示例:

    //普通函數與函數模板調用規則 void myPrint(int a, int b) {cout << "調用的普通函數" << endl; }template<typename T> void myPrint(T a, T b) { cout << "調用的模板" << endl;//函數模板重載 template<typename T> void myPrint(T a, T b, T c) { cout << "調用重載的模板" << endl; }void test01() {//1、如果函數模板和普通函數都可以實現,優先調用普通函數// 注意 如果告訴編譯器 普通函數是有的,但只是聲明沒有實現,或者不在當前文件內實現,就會報錯找不到int a = 10;int b = 20;myPrint(a, b); //調用普通函數//2、可以通過空模板參數列表來強制調用函數模板myPrint<>(a, b); //調用函數模板//3、函數模板也可以發生重載int c = 30;myPrint(a, b, c); //調用重載的函數模板//4、 如果函數模板可以產生更好的匹配,優先調用函數模板char c1 = 'a';char c2 = 'b';myPrint(c1, c2); //調用函數模板 }int main() {test01();system("pause");return 0; }

    其實我們提供函數模板了,就盡量不要再寫普通函數了,不然會出現二義性的。


    模板的局限性(函數模板的第二種實現)

    函數模板并不是萬能的,有些特定數據類型,需要用具體化方式做特殊實現。

    只有C++內置的數據類型可以直接使用前面學到的函數模板,自定義數據類型往往不能實現。

    #include<iostream> using namespace std;#include <string>class Person { public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age; };//普通函數模板 template<class T> bool myCompare(T& a, T& b) {if (a == b){return true;}else{return false;} }//具體化,顯示具體化的原型和定意思以template<>開頭,并通過名稱來指出類型 //具體化優先于常規模板 template<> bool myCompare(Person &p1, Person &p2) {if ( p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age){return true;}else{return false;} }void test01() {int a = 10;int b = 20;//內置數據類型可以直接使用通用的函數模板bool ret = myCompare(a, b);if (ret){cout << "a == b " << endl;}else{cout << "a != b " << endl;} }void test02() {Person p1("Tom", 10);Person p2("Tom", 10);//自定義數據類型,不會調用普通的函數模板//可以創建具體化的Person數據類型的模板,用于特殊處理這個類型bool ret = myCompare(p1, p2);if (ret){cout << "p1 == p2 " << endl;}else{cout << "p1 != p2 " << endl;} }int main() {test01();test02();system("pause");return 0; }

    如上,利用具體化的模板,可以解決自定義類型的通用化。


    類模板

    類模板和函數模板的區別在于模板聲明下面加的是類還是函數。

    類模板基礎語法?

    語法:

    template<typename T> 類

    解釋:

    template --- 聲明創建模板

    typename --- 表面其后面的符號是一種數據類型,可以用class代替

    T --- 通用的數據類型,名稱可以替換,通常為大寫字母

    示例:

    //類模板 // 流程://class后面緊跟著的就是通用數據類型(如果成員中需要兩個,就用逗號分隔寫兩個)//然后test01()中,在傳入的時候,用模板參數列表給這里的兩個..Type傳值//后面的兩個數據"猴哥",500;是給有參構造里面的name和age傳值//最后調用showPerson輸出 template<class NameType,class AgeType> class Person { public://寫構造函數賦初值Person(NameType name, AgeType age){this->m_Age = age;this->m_Name = name;}void showPerson(){cout << "name:" << this->m_Name << "age:" << this->m_Age << endl;}//兩個類型不一樣,需要兩個模板數據類型NameType m_Name;AgeType m_Age; };void test01() { //將類型參數化Person<string, int> p("猴哥",500);//后兩個數據是實參,傳給有參構造p.showPerson(); }int main() {test01();system("pause");return 0; }

    類模板與函數模板的區別

    問題引出(一)

    現在我們對上節示例稍微進行一下改動,把我們的顯示類型聲明給去掉。報錯

    所以類模板是沒有自動類型推導的。

    問題引出(二)

    看這里,我沒有聲明傳入int型,但是也能實現,你猜是為什么?

    ?

    ?原來,我在前面加了點“小料”。

    我在聲明模板的時候直接把AgeTyoe = int了,后面傳進去的時候就不需要說是int型了。

    所以這就是類模板在模板參數列表中可以有默認參數


    類模板中成員函數調用時機

    //類模板中成員函數創建時機 //類模板中成員函數在調用時才去創建 class Person1 { public:void showPerson1() {cout << "showPerson1函數調用" << endl;} }; class Person2 { public:void showPerson2() {cout << "showPerson2函數調用" << endl;} };//類模板 template<class T> class MyClass { public:T obj;//類模板中的成員函數void func1() {obj.showPerson1();}void func2() {obj.showPerson2();} };int main() {system("pause");return 0; }

    這里沒有調用類模板里面的成員函數,運行發現成功了。

    這兩個成員函數fuc1,func2只要不調用就不會創建,因為編譯器不知道類模板里面的obj是什么類型的。

    添加測試代碼:

    void test01() {MyClass<Person1>m;m.func1();m.func2(); }

    調用測試運行結果:

    我們調用成員函數func1,func2,就可以確定obj就是Person1的數據類型,Person1沒有showPerson2成員函數,所以會報錯。

    總結:

    ????????類模板中的成員函數并不是一開始就創建的,在調用時才去創建


    類模板對象做函數參數

    一共有三種傳入方式:

  • 指定傳入的類型 --- 直接顯示對象的數據類型

  • 參數模板化 --- 將對象中的參數變為模板進行傳遞

  • 整個類模板化 --- 將這個對象類型 模板化進行傳遞

  • #include <string> //類模板 template<class NameType, class AgeType = int> class Person { public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void showPerson(){cout << "name: " << this->mName << " age: " << this->mAge << endl;} public:NameType mName;AgeType mAge; };

    //1、指定傳入的類型 void printPerson1(Person<string, int> &p) {p.showPerson(); } void test01() {Person <string, int >p("孫悟空", 100);printPerson1(p); } //2、參數模板化 template <class T1, class T2> void printPerson2(Person<T1, T2>&p) {p.showPerson();cout << "T1的類型為: " << typeid(T1).name() << endl;cout << "T2的類型為: " << typeid(T2).name() << endl; } void test02() {Person <string, int >p("豬八戒", 90);printPerson2(p); } //3、整個類模板化 template<class T> void printPerson3(T & p) {cout << "T的類型為: " << typeid(T).name() << endl;p.showPerson();} void test03() {Person <string, int >p("唐僧", 30);printPerson3(p); }

    類模板與繼承

    當類模板碰到繼承時,需要注意一下幾點:

    • 當子類繼承的父類是一個類模板時,子類在聲明的時候,要指定出父類中T的類型

    • 如果不指定,編譯器無法給子類分配內存

    • 如果想靈活指定出父類中T的類型,子類也需變為類模板

    示例:

    template<class T> class Base {T m; };//class Son:public Base //錯誤,c++編譯需要給子類分配內存,必須知道父類中T的類型才可以向下繼承 class Son :public Base<int> //必須指定一個類型 { }; void test01() {Son c; }//類模板繼承類模板 ,可以用T2指定父類中的T類型 template<class T1, class T2>//想要靈活的指定父類中的T類型,子類也需要變成類模板 class Son2 :public Base<T2> { public:Son2(){cout << typeid(T1).name() << endl;cout << typeid(T2).name() << endl;} };void test02() {Son2<int, char> child1; }int main() {test01();test02();system("pause");return 0; }

    類模板成員函數類外實現

    類模板中成員函數類外實現時,需要加上模板參數列表。?

    #include <string>template<class T1, class T2> class Person { public://成員函數類內聲明Person(T1 name, T2 age);void showPerson();public:T1 m_Name;T2 m_Age; };//構造函數 類外實現 template<class T1, class T2> Person<T1, T2>::Person(T1 name, T2 age) {this->m_Name = name;this->m_Age = age; }//成員函數 類外實現 template<class T1, class T2> void Person<T1, T2>::showPerson() {cout << "姓名: " << this->m_Name << " 年齡:" << this->m_Age << endl; }void test01() {Person<string, int> p("Tom", 20);p.showPerson(); }int main() {test01();system("pause");return 0; }

    類模板與友元

    全局函數類內實現 - 直接在類內聲明友元即可

    全局函數類外實現 - 需要提前讓編譯器知道全局函數的存在

    #include <string>//2、全局函數配合友元 類外實現 - 先做函數模板聲明,下方在做函數模板定義,在做友元 template<class T1, class T2> class Person;//如果聲明了函數模板,可以將實現寫到后面,否則需要將實現體寫到類的前面讓編譯器提前看到 //template<class T1, class T2> void printPerson2(Person<T1, T2> & p); template<class T1, class T2> void printPerson2(Person<T1, T2> & p) {cout << "類外實現 ---- 姓名: " << p.m_Name << " 年齡:" << p.m_Age << endl; }template<class T1, class T2> class Person {//1、全局函數配合友元 類內實現friend void printPerson(Person<T1, T2> & p){cout << "姓名: " << p.m_Name << " 年齡:" << p.m_Age << endl;}//全局函數配合友元 類外實現friend void printPerson2<>(Person<T1, T2> & p);public:Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}private:T1 m_Name;T2 m_Age;};//1、全局函數在類內實現 void test01() {Person <string, int >p("Tom", 20);printPerson(p); }//2、全局函數在類外實現 void test02() {Person <string, int >p("Jerry", 30);printPerson2(p); }int main() {//test01();test02();system("pause");return 0; }

    總結

    以上是生活随笔為你收集整理的C++模板 —— 万字带你了解C++模板(蓝桥杯算法比赛必备知识STL基础)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。