函数模板
函数模板的概念
为了提高效率,实现代码复用,C++提供了一种处理机制,即使用函数模板。
定义函数模板的格式
template <模板参数表>
返回类型名 函数模板名(参数表)
{
函数体的定义
}
函数模板的定义以关键字template开头,该关键字之后是使用尖括号<>括起来的”模板参数表“。
函数模板中函数体的定义方式与定义普通函数时类似。
函数模板的示例
程序9-1 定义求绝对值的函数模板并进行不同的调用
#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
函数指针只能指向模板的实例,而不能指向模板本身。
程序9-2 定义对象交换的函数模板
#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;
}
显式实例化函数模板的格式
模板名 <实际类型参数1,实际类型参数2,...>
例如,程序9-2主函数中可以写成
Swap<int>(n,m);
Swap<myDate>(d1,d2);
函数模板可以带多个类型参数。
template <class T1,class T2>
void print(T1 arg1,T2 arg2)
{
cout<<arg1<<", "<<arg2<<endl;
}
例9-1 定义对象比较的函数模板
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,
函数或函数模板调用语句的匹配顺序
函数模板可以重载,只要他们的形参表不同即可。
程序9-4 重载函数模板
#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 函数调用匹配顺序
#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 <模板参数表>
class 类模板名
{
类体定义
}
如果需要在类模板以外定义其成员函数,则需要采用以下格式
template <模板参数表>
返回类型名 类模板名<模板参数标识符列表>::成员函数名(参数表)
{
函数体
}
当使用类模板创建对象时,要随类模板名给出对应于类型形参或普通形参的具体实参,格式
类模板名 <模板参数表> 对象名1,...,对象名n;
或
类模板名 <模板参数表> 对象名1(构造函数实参),...,对象名n(构造函数实参);
编译器由类模板生成类的过程称为类模板的实例化。由类模板实例化得到的类称为模板类。
类模板示例
程序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的成员函数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类型的数据成员buffer数组大小固定为10
T getData(int j); //获取T类型buffer(数组)的第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 在类模板中使用函数模板
#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的成员函数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 类模板中使用静态成员
#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 使用普通参数的类模板
#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::