函數(shù)模板
函數(shù)模板的概念
為了提高效率董朝,實現(xiàn)代碼復用鸠项,C++提供了一種處理機制,即使用函數(shù)模板子姜。
定義函數(shù)模板的格式
template <模板參數(shù)表>
返回類型名 函數(shù)模板名(參數(shù)表)
{
函數(shù)體的定義
}
函數(shù)模板的定義以關鍵字template開頭祟绊,該關鍵字之后是使用尖括號<>括起來的”模板參數(shù)表“。
函數(shù)模板中函數(shù)體的定義方式與定義普通函數(shù)時類似哥捕。
函數(shù)模板的示例
程序9-1 定義求絕對值的函數(shù)模板并進行不同的調用
#include <iostream>
using namespace std;
template <typename T>
T abs(T x)
{
return x<0?-x:x;
}
int main()
{
int n = -5;
int m = 10;
double d = -5;
float f = 3.2;
cout<<n<<"的絕對值是: "<<abs(n)<<endl;
cout<<m<<"的絕對值是: "<<abs(m)<<endl;
cout<<d<<"的絕對值是: "<<abs(d)<<endl;
cout<<f<<"的絕對值是: "<<abs(f)<<endl;
return 0;
}
-5的絕對值是: 5
10的絕對值是: 10
-5的絕對值是: 5
3.2的絕對值是: 3.2
函數(shù)指針只能指向模板的實例牧抽,而不能指向模板本身。
程序9-2 定義對象交換的函數(shù)模板
#include <iostream>
using namespace std;
template <class T>
void Swap(T &x,T &y)
{
T tmp = x;
x = y;
y = tmp;
}
class myDate
{
public:
myDate();
myDate(int,int,int);
void printDate() const;
private:
int year,month,day;
};
myDate::myDate()
{
year = 1970;
month = 1;
day = 1;
}
myDate::myDate(int y,int m,int d)
{
year = y;
month = m;
day = d;
}
void myDate::printDate()const
{
cout<<year<<"/"<<month<<"/"<<day;
return;
}
int main()
{
int n = 1,m = 2;
Swap(n,m);
double f = 1.2,g = 2.3;
Swap(f,g);
myDate d1,d2(2000,1,1);
Swap(d1,d2);
return 0;
}
顯式實例化函數(shù)模板的格式
模板名 <實際類型參數(shù)1遥赚,實際類型參數(shù)2扬舒,...>
例如,程序9-2主函數(shù)中可以寫成
Swap<int>(n,m);
Swap<myDate>(d1,d2);
函數(shù)模板可以帶多個類型參數(shù)凫佛。
template <class T1,class T2>
void print(T1 arg1,T2 arg2)
{
cout<<arg1<<", "<<arg2<<endl;
}
例9-1 定義對象比較的函數(shù)模板
template <typename T>
int myCompare(const T& left,const T& right)
{
if(left<right)
{
return -1;
}
else if(right < left)
{
return 1;
}
else return 0;
}
程序9-3 對象排序程序
#include <iostream>
using namespace std;
template <typename T>
int myCompare(const T& left,const T& right)
{
if(left<right)
{
return -1;
}
else if(right < left)
{
return 1;
}
else return 0;
}
template <class T>
void Swap(T &x,T &y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
string arraystring[10] = {"shang","xia","zuo","you","qian","hou","dong","xi","nan","bei"};
int j;
string temp;
for(int i=1;i<10;i++)
{
j = i;
while(j>0&&myCompare<string>(arraystring[j-1],arraystring[j])>0)
{
Swap(arraystring[j],arraystring[j-1]);
j--;
}
}
for(int i = 0;i<10;i++)
cout<<arraystring[i]<<",";
}
bei,dong,hou,nan,qian,shang,xi,xia,you,zuo,
函數(shù)或函數(shù)模板調用語句的匹配順序
函數(shù)模板可以重載讲坎,只要他們的形參表不同即可。
程序9-4 重載函數(shù)模板
#include <iostream>
using namespace std;
class myDate
{
public:
myDate();
myDate(int,int,int);
friend ostream & operator<<(ostream & os,const myDate & c); //友元愧薛,插入
private:
int year,month,day;
};
myDate::myDate()
{
year = 1970;
month = 1;
day = 1;
}
myDate::myDate(int y,int m,int d)
{
year = y;
month = m;
day = d;
}
ostream & operator<<(ostream & os,const myDate & c)
{
os<<c.year<<"/"<<c.month<<"/"<<c.day;
return os;
}
template <class T1,class T2>
void print(T1 arg1,T2 arg2)
{
cout<<arg1<<", "<<arg2<<endl;
}
template <class T>
void print(T arg1,T arg2)
{
cout<<arg1<<", "<<arg2<<endl;
}
int main()
{
int n = 1,m = 2;
print(n,m); //輸出1晨炕, 2
myDate d1,d2(2000,1,1);
print(d1,d2);
print(n,d1);
return 0;
}
1, 2
1970/1/1, 2000/1/1
1, 1970/1/1
程序9-5 函數(shù)調用匹配順序
#include <iostream>
using namespace std;
template <class T>
T Max(T a,T b)
{
cout<<"Template Max 1"<<endl;
return 0;
}
template <class T,class T2>
T Max(T a,T2 b)
{
cout<<"Template Max 2"<<endl;
return 0;
}
double Max(double a,double b)
{
cout<<"Function Max"<<endl;
return 0;
}
int main()
{
int i=4,j=5;
Max(1.2,3.4);
Max(i,j);
Max(1.2,3);
return 0;
}
Function Max
Template Max 1
Template Max 2
類模板
當需要編寫多個形式和功能都相似的類時,可以使用類模板機制毫炉。
類是對一組對象的公共性質的抽象瓮栗,而類模板則是對不同類的公共性質的抽象,因此類模板是屬于更高層次的抽象瞄勾。
通過類模板遵馆,可以實例化一個個的類。
聲明類模板的格式
template <模板參數(shù)表>
class 類模板名
{
類體定義
}
如果需要在類模板以外定義其成員函數(shù)丰榴,則需要采用以下格式
template <模板參數(shù)表>
返回類型名 類模板名<模板參數(shù)標識符列表>::成員函數(shù)名(參數(shù)表)
{
函數(shù)體
}
當使用類模板創(chuàng)建對象時货邓,要隨類模板名給出對應于類型形參或普通形參的具體實參,格式
類模板名 <模板參數(shù)表> 對象名1,...,對象名n;
或
類模板名 <模板參數(shù)表> 對象名1(構造函數(shù)實參),...,對象名n(構造函數(shù)實參);
編譯器由類模板生成類的過程稱為類模板的實例化四濒。由類模板實例化得到的類稱為模板類换况。
類模板示例
程序9-6 類模板
#include <iostream>
#include <string>
using namespace std;
template <class T1,class T2>
class Pair
{
public:
T1 first;
T2 second;
Pair(T1 k,T2 v):first(k),second(v){}
bool operator<(const Pair<T1,T2>& p)const;
};
template <class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2> & p) const //Pair的成員函數(shù)operator<
{
return first<p.first;
}
int main()
{
Pair<string,int> student1("Tom",19);
Pair<string,int>student2("Jim",21);
Pair<int,int>coordinate(10,20);
Pair<string,string>dic("word","單詞");
cout<<"學生1:"<<student1.first<<" "<<student1.second<<endl;
cout<<"學生2:"<<student2.first<<" "<<student2.second<<endl;
cout<<"坐標: "<<coordinate.first<<" "<<coordinate.second<<endl;
cout<<"字典項: "<<dic.first<<" "<<dic.second<<endl;
bool a = student1<student2;
if(a==0)cout<<student1.first<<"位于"<<student2.first<<"之后"<<endl;
else cout<<student1.first<<"位于"<<student2.first<<"之前"<<endl;
return 0;
}
學生1:Tom 19
學生2:Jim 21
坐標: 10 20
字典項: word 單詞
Tom位于Jim之后
程序9-7 類模板
#include <iostream>
using namespace std;
template <class T>
class TestClass
{
public:
T buffer[10]; //T類型的數(shù)據(jù)成員buffer數(shù)組大小固定為10
T getData(int j); //獲取T類型buffer(數(shù)組)的第j個分量
};
template <class T>
T TestClass<T>::getData(int j)
{
return *(buffer+j);
}
int main()
{
TestClass<char> ClassInstA;
int i;
char cArr[6] = "abcde";
for(i=0;i<5;i++)
ClassInstA.buffer[i] = cArr[i];
for(i = 0;i<5;i++)
{
char res = ClassInstA.getData(i);
cout<<res<<" ";
}
cout<<endl;
TestClass<double> ClassInstF;
double fArr[6] = {12.1,23.2,34.3,45.4,56.5,67.6};
for(i=0;i<6;i++)
ClassInstF.buffer[i]=fArr[i]-10;
for(i=0;i<6;i++)
{
double res = ClassInstF.getData(i);
cout<<res<<" ";
}
cout<<endl;
return 0;
}
a b c d e
2.1 13.2 24.3 35.4 46.5 57.6
程序9-8 在類模板中使用函數(shù)模板
#include <iostream>
#include <string>
using namespace std;
template <class T1,class T2>
class Pair
{
public:
T1 first;
T2 second;
Pair(T1 k,T2 v):first(k),second(v){}
bool operator<(const Pair<T1,T2>& p)const;
template <class T>
void print(T x)
{
cout<<x<<endl;
}
};
template <class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2> & p) const //Pair的成員函數(shù)operator<
{
return first<p.first;
}
int main()
{
Pair<string,int> student1("Tom",19);
Pair<string,int>student2("Jim",21);
Pair<int,int>coordinate(10,20);
Pair<string,string>dic("word","單詞");
cout<<"學生1:"<<student1.first<<" "<<student1.second<<endl;
cout<<"學生2:"<<student2.first<<" "<<student2.second<<endl;
cout<<"坐標: "<<coordinate.first<<" "<<coordinate.second<<endl;
cout<<"字典項: "<<dic.first<<" "<<dic.second<<endl;
bool a = student1<student2;
if(a==0)cout<<student1.first<<"位于"<<student2.first<<"之后"<<endl;
else cout<<student1.first<<"位于"<<student2.first<<"之前"<<endl;
student1.print<string>(student1.first);
coordinate.print<int>(coordinate.first);
return 0;
}
學生1:Tom 19
學生2:Jim 21
坐標: 10 20
字典項: word 單詞
Tom位于Jim之后
Tom
10
程序9-9 類模板中使用靜態(tài)成員
#include <iostream>
using namespace std;
template <typename T>
class Test
{
public:
Test(T num)
{
k += num;
}
Test()
{
k += 1;
}
static void incrementK()
{
k += 1;
}
static T k;
};
template <typename T>
T Test<T>::k = 0;
int main()
{
// static Field;
Test<int> a;
Test<double>b(4);
cout<<"Test<int>::\tk="<<a.k<<endl;
cout<<"Test<double>::\tk="<<Test<double>::k<<endl;
Test<int> v;
Test<double> m;
cout<<"Test<int>::\tk="<<Test<int>::k<<endl;
cout<<"Test<double>::\tk="<<Test<double>::k<<endl;
// static Function
cout<<endl;
Test<int>::incrementK();
cout<<"調用Test<int>::incrementK() Test<int>::k="<<Test<int>::k<<endl;
Test<double>::incrementK();
cout<<"調用Test<double>::incrementK() Test<double>::k="<<Test<double>::k<<endl;
return 0;
}
Test<int>:: k=1
Test<double>:: k=4
Test<int>:: k=2
Test<double>:: k=5
調用Test<int>::incrementK() Test<int>::k=3
調用Test<double>::incrementK() Test<double>::k=6
程序9-10 使用普通參數(shù)的類模板
#include <iostream>
using namespace std;
template <int i>
class TestClass
{
public:
int buffer[i];
int getData(int j);
};
template <int i>
int TestClass<i>::getData(int j)
{
return *(buffer+j);
};
int main()
{
TestClass<6> ClassInstF;
int i;
double fArr[6]={12.1,23.2,34.3,45.4,56.5,67.6};
for(i=0;i<6;i++)
ClassInstF.buffer[i] = fArr[i]-10;
for(i=0;i<6;i++)
{
double res = ClassInstF.getData(i);
cout<<res<<" ";
}
cout<<endl;
}
2 13 24 35 46 57
類模板與繼承
類模板和類模板之間职辨、類模板和類之間可以互相繼承,他們之間的常見派生關系有:
- 普通類繼承模板類戈二。
- 類模板繼承普通類舒裤。
- 類模板繼承類模板。
- 類模板繼承模板類觉吭。
程序9-11 普通類繼承模板類
#include <iostream>
using namespace std;
template<class T>
class TBase //類模板腾供,基類
{
T data;
public:
void print()
{
cout<<data<<endl;
}
};
class Derived:public TBase<int> //從模板類繼承,普通類
{
};
int main()
{
Derived d;
d.print();
}
0
程序9-12 類模板繼承普通類
#include <iostream>
using namespace std;
class TBase //基類鲜滩,普通類
{
int k;
public:
void print()
{
cout<<"TBase::"<<k<<endl;
}
};
template<class T>
class TDerived:public TBase //派生類伴鳖,類模板
{
T data;
public:
void setData(T x)
{
data = x;
}
void print()
{
TBase::print();
cout<<"TDerived::"<<data<<endl;
}
};
int main()
{
TDerived<string> d;
d.setData("2019");
d.print();
}
TBase::1
TDerived::2019
程序9-13 類模板繼承類模板
#include <iostream>
using namespace std;
template<class T>
class TBase //類模板
{
T data1;
public:
void print()
{
cout<<"TBase::"<<data1<<endl;
}
};
template <class T1,class T2>
class TDerived:public TBase<T1> //派生類,類模板
{
T2 data2;
public:
void print()
{
TBase<T1>::print();
cout<<"TDerived::"<<data2<<endl;
}
};
int main()
{
TDerived<int,int> d;
d.print();
TDerived<string,string> d2;
d2.print();
}
TBase::0
TDerived::0
TBase::
TDerived::
程序9-14 類模板繼承模板類
#include <iostream>
using namespace std;
template<class T>
class TBase
{
T data1;
public:
void print()
{
cout<<"TBase::"<<data1<<endl;
}
};
template <class T2>
class TDerived:public TBase<int>
{
T2 data2;
public:
void print()
{
TBase<int>::print();
cout<<"TDerived::"<<data2<<endl;
}
};
int main()
{
TDerived<int> d;
d.print();
TDerived<string>d2;
d2.print();
}
TBase::0
TDerived::0
TBase::1
TDerived::