C++類模板


一、類模板

1、作用

建立一個通用類,類中的成員 數據類型可以不具體制定,用一個虛擬的類型來代表。

2、語法

template<typename T>

template --- 聲明創建模板

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

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

 

二、類模板和函數模板的區別

1、 類模板沒有自動類型推導的使用方式

2、 類模板在模板參數列表中可以有默認參數

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 5; //類模板
template <class NameType=string, 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 test01() { // Person p("孫悟空", 1000); // 錯誤 類模板使用時候,不可以用自動類型推導
    Person<string, int> p("孫悟空", 1000); //必須使用顯示指定類型的方式,使用類模板
 p.showPerson(); } //2、類模板在模板參數列表中可以有默認參數
void test02() { Person<> p("豬八戒", 999); //類模板中的模板參數列表 可以指定默認參數
 p.showPerson(); } int main() { test01(); test02(); system("pause"); return 0; }

三、類模板中成員函數創建時機

類模板中成員函數和普通類中成員函數創建時機是有區別的:

1、普通類中的成員函數一開始就可以創建

2、類模板中的成員函數在調用時才創建

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 5; class Person1 { public: void showPerson1() { cout << "Person1 show" << endl; } }; class Person2 { public: void showPerson2() { cout << "Person2 show" << endl; } }; template <class T>
class MyClass { public: T obj; //類模板中的成員函數,並不是一開始就創建的,而是在模板調用時再生成
    void fun1() { obj.showPerson1(); } void fun2() { obj.showPerson2(); } }; void test01() { MyClass<Person1> m; m.fun1(); //m.fun2();//編譯會出錯,說明函數調用才會去創建成員函數
} int main() { test01(); system("pause"); return 0; }

四、類模板對象做函數參數

一共有三種傳入方式:

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

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

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

一般使用第一種方式,因為比較簡易

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(); }

其他兩種:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e5 + 5;
 4 //類模板
 5 template <class NameType, class AgeType = int>
 6 class Person
 7 {
 8 public:
 9     Person(NameType name, AgeType age)
10     {
11         this->mName = name;
12         this->mAge = age;
13     }
14     void showPerson()
15     {
16         cout << "name: " << this->mName << " age: " << this->mAge << endl;
17     }
18 
19 public:
20     NameType mName;
21     AgeType mAge;
22 };
23 //1、指定傳入的類型
24 void printPerson1(Person<string, int> &p)
25 {
26     p.showPerson();
27 }
28 void test01()
29 {
30     Person<string, int> p("孫悟空", 100);
31     printPerson1(p);
32 }
33 //2、參數模板化
34 template <class T1, class T2>
35 void printPerson2(Person<T1, T2> &p)
36 {
37     p.showPerson();
38     cout << "T1的類型為: " << typeid(T1).name() << endl;
39     cout << "T2的類型為: " << typeid(T2).name() << endl;
40 }
41 void test02()
42 {
43     Person<string, int> p("豬八戒", 90);
44     printPerson2(p);
45 }
46 //3、整個類模板化
47 template <class T>
48 void printPerson3(T &p)
49 {
50     cout << "T的類型為: " << typeid(T).name() << endl;
51     p.showPerson();
52 }
53 void test03()
54 {
55     Person<string, int> p("唐僧", 30);
56     printPerson3(p);
57 }
58 int main()
59 {
60     test01();
61     test02();
62     test03();
63     system("pause");
64     return 0;
65 }
View Code

 

五、類模板與繼承

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

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

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

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

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 5; 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>
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 <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 5; //類模板中成員函數類外實現
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; }

七、類模板分文件編寫

問題:類模板中成員函數創建時機是在調用階段,導致分文件編寫時鏈接不到

解決:

1、直接包含.cpp源文件

2、將聲明和實現寫到同一個文件中,並更改后綴名為.hpp,hpp是約定的名稱,並不是強制

person.hpp

#pragma once #include <iostream>
using namespace std; #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; }

類模板分文件編寫.cpp中代碼

#include <bits/stdc++.h>
using namespace std; #include "person.cpp" //解決方式1,包含cpp源文件 //解決方式2,將聲明和實現寫到一起,文件后綴名改為.hpp
#include "person.hpp"
void test01() { Person<string, int> p("Tom", 10); p.showPerson(); } int main() { test01(); system("pause"); return 0; }

八、類模板與友元

1、全局函數類內實現 - 直接在類內聲明友元即可(這個實現起來簡單)

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

#include <bits/stdc++.h>
using namespace std; //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; }

 


免責聲明!

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



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