函数模板
函数模板的概念
为了提高效率,实现代码复用,C++提供了一种处理机制,即使用函数模板。
定义函数模板的格式
template <模板参数表>
返回类型名 函数模板名(参数表)
{
函数体的定义
}
函数模板的定义以关键字template开头,该关键字之后是使用尖括号<>括起来的”模板参数表“。
函数模板中函数体的定义方式与定义普通函数时类似。
函数模板的示例
程序9-1 定义求绝对值的函数模板并进行不同的调用
#include
using namespace std;
template
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<
函数指针只能指向模板的实例,而不能指向模板本身。
程序9-2 定义对象交换的函数模板
#include
using namespace std;
template
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<
显式实例化函数模板的格式
模板名 <实际类型参数1,实际类型参数2,...>
例如,程序9-2主函数中可以写成
Swap(n,m);
Swap(d1,d2);
函数模板可以带多个类型参数。
template
void print(T1 arg1,T2 arg2)
{
cout<
例9-1 定义对象比较的函数模板
template
int myCompare(const T& left,const T& right)
{
if(left
程序9-3 对象排序程序
#include
using namespace std;
template
int myCompare(const T& left,const T& right)
{
if(left
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(arraystring[j-1],arraystring[j])>0)
{
Swap(arraystring[j],arraystring[j-1]);
j--;
}
}
for(int i = 0;i<10;i++)
cout<
函数或函数模板调用语句的匹配顺序
函数模板可以重载,只要他们的形参表不同即可。
程序9-4 重载函数模板
#include
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<
void print(T1 arg1,T2 arg2)
{
cout<
void print(T arg1,T arg2)
{
cout<
程序9-5 函数调用匹配顺序
#include
using namespace std;
template
T Max(T a,T b)
{
cout<<"Template Max 1"<
T Max(T a,T2 b)
{
cout<<"Template Max 2"<
类模板
当需要编写多个形式和功能都相似的类时,可以使用类模板机制。
类是对一组对象的公共性质的抽象,而类模板则是对不同类的公共性质的抽象,因此类模板是属于更高层次的抽象。
通过类模板,可以实例化一个个的类。
声明类模板的格式
template <模板参数表>
class 类模板名
{
类体定义
}
如果需要在类模板以外定义其成员函数,则需要采用以下格式
template <模板参数表>
返回类型名 类模板名<模板参数标识符列表>::成员函数名(参数表)
{
函数体
}
当使用类模板创建对象时,要随类模板名给出对应于类型形参或普通形参的具体实参,格式
类模板名 <模板参数表> 对象名1,...,对象名n;
或
类模板名 <模板参数表> 对象名1(构造函数实参),...,对象名n(构造函数实参);
编译器由类模板生成类的过程称为类模板的实例化。由类模板实例化得到的类称为模板类。
类模板示例
程序9-6 类模板
#include
#include
using namespace std;
template
class Pair
{
public:
T1 first;
T2 second;
Pair(T1 k,T2 v):first(k),second(v){}
bool operator<(const Pair& p)const;
};
template
bool Pair::operator<(const Pair & p) const //Pair的成员函数operator<
{
return first student1("Tom",19);
Pairstudent2("Jim",21);
Paircoordinate(10,20);
Pairdic("word","单词");
cout<<"学生1:"<
程序9-7 类模板
#include
using namespace std;
template
class TestClass
{
public:
T buffer[10]; //T类型的数据成员buffer数组大小固定为10
T getData(int j); //获取T类型buffer(数组)的第j个分量
};
template
T TestClass::getData(int j)
{
return *(buffer+j);
}
int main()
{
TestClass 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< 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<
程序9-8 在类模板中使用函数模板
#include
#include
using namespace std;
template
class Pair
{
public:
T1 first;
T2 second;
Pair(T1 k,T2 v):first(k),second(v){}
bool operator<(const Pair& p)const;
template
void print(T x)
{
cout<
bool Pair::operator<(const Pair & p) const //Pair的成员函数operator<
{
return first student1("Tom",19);
Pairstudent2("Jim",21);
Paircoordinate(10,20);
Pairdic("word","单词");
cout<<"学生1:"<(student1.first);
coordinate.print(coordinate.first);
return 0;
}
学生1:Tom 19
学生2:Jim 21
坐标: 10 20
字典项: word 单词
Tom位于Jim之后
Tom
10
程序9-9 类模板中使用静态成员
#include
using namespace std;
template
class Test
{
public:
Test(T num)
{
k += num;
}
Test()
{
k += 1;
}
static void incrementK()
{
k += 1;
}
static T k;
};
template
T Test::k = 0;
int main()
{
// static Field;
Test a;
Testb(4);
cout<<"Test::\tk="<::\tk="<::k< v;
Test m;
cout<<"Test::\tk="<::k<::\tk="<::k<::incrementK();
cout<<"调用Test::incrementK() Test::k="<::k<::incrementK();
cout<<"调用Test::incrementK() Test::k="<::k<:: k=1
Test:: k=4
Test:: k=2
Test:: k=5
调用Test::incrementK() Test::k=3
调用Test::incrementK() Test::k=6
程序9-10 使用普通参数的类模板
#include
using namespace std;
template
class TestClass
{
public:
int buffer[i];
int getData(int j);
};
template
int TestClass::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<
类模板与继承
类模板和类模板之间、类模板和类之间可以互相继承,他们之间的常见派生关系有:
- 普通类继承模板类。
- 类模板继承普通类。
- 类模板继承类模板。
- 类模板继承模板类。
程序9-11 普通类继承模板类
#include
using namespace std;
template
class TBase //类模板,基类
{
T data;
public:
void print()
{
cout< //从模板类继承,普通类
{
};
int main()
{
Derived d;
d.print();
}
0
程序9-12 类模板继承普通类
#include
using namespace std;
class TBase //基类,普通类
{
int k;
public:
void print()
{
cout<<"TBase::"<
class TDerived:public TBase //派生类,类模板
{
T data;
public:
void setData(T x)
{
data = x;
}
void print()
{
TBase::print();
cout<<"TDerived::"< d;
d.setData("2019");
d.print();
}
TBase::1
TDerived::2019
程序9-13 类模板继承类模板
#include
using namespace std;
template
class TBase //类模板
{
T data1;
public:
void print()
{
cout<<"TBase::"<
class TDerived:public TBase //派生类,类模板
{
T2 data2;
public:
void print()
{
TBase::print();
cout<<"TDerived::"< d;
d.print();
TDerived d2;
d2.print();
}
TBase::0
TDerived::0
TBase::
TDerived::
程序9-14 类模板继承模板类
#include
using namespace std;
template
class TBase
{
T data1;
public:
void print()
{
cout<<"TBase::"<
class TDerived:public TBase
{
T2 data2;
public:
void print()
{
TBase::print();
cout<<"TDerived::"< d;
d.print();
TDerivedd2;
d2.print();
}
TBase::0
TDerived::0
TBase::1
TDerived::