1、引言
在寫排序算法時,若是要寫一個交換兩個數據的函數,因爲基本數據類型有int、float、double等等類型,因此針對每種數據類型可能咱們要寫不少swap函數,這些函數除了傳入的數據類型不一樣,函數體結構大體相同。因此C++爲了不讓程序員寫不少大量重複代碼,設計了一種叫作「模板」的東西。咱們寫程序時,先不指定什麼類型,在調用時咱們再說明一下是什麼類型,具體怎麼實現接着往下看。程序員
2、函數模板
一、定義
像開頭所說,若是要對int、double類型的兩個數進行交換咱們要寫兩個函數,但用函數模板時只須要寫一個函數便可。模板定義以下:算法
template <typename T>
或者函數
template <class T>
其中,template是聲明一個模板,typename是聲明一個虛類型T,這個T能夠代替int、double等基本數據類型,那爲何還有class?由於最初是用class聲明一個T來表示通用數據類型,但考慮到class會和「類」混淆,就改用typename進行定義,同時保留了class,這二者效果相同,但我我的比較習慣用class。this
在進行聲明模板以後下面就開始寫模板的函數體了,例如交換函數,合起來就是:設計
template <class T>
void swap(T *p1,T *p2){
T temp=*p1;
*p1=*p2;
*p2=temp;
}對象
這樣就是一個完整的函數模板排序
二、調用
有兩種方式使用模板繼承
(1)自動類型推導:編譯器會自動斷定你傳入的數據是什麼數據類型,而後將T改爲對應數據類型進行操做;內存
(2)本身聲明數據類型進行調用,具體實現以下:編譯器
//一、自動類型推導
swap(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
//二、顯示指定類型
swap<int>(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
什麼時候必須本身聲明數據類型呢?
那就是沒有參數傳遞的時候。好比知識一個打印函數,沒有參數傳遞,這裏就不寫代碼了。
三、多個虛類型
前面是針對一個函數裏面都是同一數據類型的,若是含有不一樣數據類型,假若有兩個:
template<class T1,class T2>
void func(T1 a,T2 b){....}
1
2
調用時能夠自動識別類型也能夠本身聲明數據類型:
func<int,double>(1,3.14);
1
3、類模板
前面已經介紹了模板大體的做用,這裏對類模板就不作過多說明,直接上乾貨:
一、定義
咱們定一個學生類
template<class T1,class T2,class T3>
class Student{
public:
Student(T1 name,T2 age,T3 score){
..........
}
T1 m_Name;
T2 m_Age;
T3 m_Score;
}
二、調用
調用時必須指定輸入了什麼數據,也就是尖括號不能省略,這點與函數模板不同
Student<string,int,float>s("Tom",18,85.5);
1
4、類的函數模板
在類內定義的話就跟前面的函數模板同樣,若是在類外定義,類外也要寫上函數模板的形式:
template<class numType>
class Compare{
public:
Compare(numType a,numType b){
this->a=a;
this->b=b;
}
//聲明模板函數:
numType max( );
private:
numType a;
numTypr b;
}
//類外定義模板函數
template<class numType>
numType Compare::max( ){
return this->a>this->b?this->a:this->b;
}
5、類做爲數據類型傳入
//定義Person1
class Person1 {
public:
void showPerson1() {
cout << "Person1 show" << endl;
}
};
//定義Person2
class Person2 {
public:
void showPerson2() {
cout << "Person2 show" << endl;
}
};
//定義類模板
template<class T>
class MyClass {
public:
T obj;
//類模板中的成員函數
void func1() {
obj.showPerson1();
}
void func2() {
obj.showPerson2();
}
};
//主函數
int main() {
MyClass<Person1>m;
m.func1();
//m.func2();//會報錯,由於「showPerson2」: 不是「Person1」的成員
system("pause");
return 0;
}
6、類模板與繼承
若是父類是一個模板,子類繼承父類模板的時候,不知道父類模板內存是多少,編譯器就沒法給子類分配內存,解決方案是給子類也加上模板,方案以下:
template<class T>
class Base {
T m_Name;
};
//class Son :public Base { //錯誤,必須知道T的內存才能指定空間
class Son1:public Base<int>{ // 不靈活
};
//想要靈活指定父類中T的類型
template<class T1,class T2>
class Son2 :public Base<T2> {
public:
T1 m_A;
};
int main() {
//讓子類的T爲string,子類的T1爲int
Son2<int, string>s2;
system("pause");
return 0;
}
7、類模板與友元
前面也有過傳入類對象到函數裏面,若是這個函數須要用到對象裏面的數據,而該數據有被設定爲private(私有)就沒法直接訪問,此時又要用到友元函數的知識:
注意:類內添加友元函數後,若是沒有對該友元函數進行聲明,編譯器認爲你沒有這個函數,會進行報錯。
//先聲明類和函數,防止編譯器報錯
template<class T1,class T2>
class Person;
template<class T1, class T2>
void printPerson(Person<T1, T2> p);
template<class T1,class T2>
class Person {
//全局函數類外實現的聲明
friend void printPerson<>(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;
};
//全局函數類外實現
template<class T1,class T2>
void printPerson(Person<T1, T2> p) {
cout << "Name:" << p.m_Name << endl;
cout << "Age:" << p.m_Age << endl;
}
以爲有用記得頂一下哦_