模板概述
C 有两种模板机制:函数模板和类模板。模板中的参数也称为类属参数。 模板、模板类、对象和模板函数之间的关系:
函数模板
函数模板是对一组函数的描述,他不是一个真实的函数,编译系统并不产生任何执行代码。当编译系统在程序中发现有与函数模板中相匹配的函数调用时,便产生一个重载函数,该重载函数的函数体与函数模板的函数体相同,该重载函数就是模板函数。
声明模板函数
声明函数模板格式:
代码语言:javascript复制template 类型形参表//类型形参表可以包含基本数据类型,也可以包含类类型
返回类型 函数名(形参表)//形参表中的参数是唯一的,而且在函数定义时至少出现一次
{
函数体;
}//在template语句与函数模板声明之间不允许有别的语句
编写函数模板
1.定义一个普通的函数,数据类型采用普通的数据类型
代码语言:javascript复制//求绝对值函数模板
int abs(int x)
{ if(x<0) return -x;
else return x;
}
2.将数据类型参数化,将其中具体的数据类型名全部替换成由自己定义的抽象的类型参数名。
代码语言:javascript复制//以上边函数模板为例
T abs(T x)
{ if (x<0) return -x;
else return x;
}
3.在函数头前用关键字template引出对函数参数名的定义。
代码语言:javascript复制template <class T>
T abs(T x)
{ if(x<0) return -x;
else return x;
}
使用函数模板
函数模板不能直接执行,需要实例化为模板函数后才能够执行。
代码语言:javascript复制#include<iostream>
using namespace std;
template <class T>
T min(T x, T y)
{
if (x < y) return x;
else return y;
}
void main()
{
int n1 = 2, n2 = 10;
double d1 = 2.3, d2 = 2.2;
cout << "较小整数" << min(n1, n2) << endl;
cout << "较小实数" << min(d1, d2) << endl;
system("pause");
}
函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。将数据类型形参实例化的参数称为模板实参,用模板实参实例化的函数就是模板函数。模板函数的生成就是将函数模板的类型形参实例化的过程。
自定义参数类型
可以在函数模板的“形参表”和对模板函数的调用中使用类的类型和其他用户定义的类型。如果这样,就必须在类中设计重载运算符,以便模板函数能对类变量进行正确的运算,否则就会出现错误。
代码语言:javascript复制#include<iostream>
using namespace std;
class MyClass
{
int x, y;
public:
MyClass(int x1, int y1)
{
x = x1; y = y1;
}
int getx(){ return x; }
int gety(){ return y; }
int operator<(MyClass &c);
};
int MyClass::operator<(MyClass &c)
{
if (x < c.x&&y < c.y)
return 1;
else return 0;
}
template<class T>
T &min(T &o1, T &o2)
{
if (o1 < o2)
return o1;
else return o2;
}
void main()
{
MyClass s1(5, 9);
MyClass s2(6, 12);
MyClass s3=min(s1, s2);
cout << "较小的坐标:(" << s3.getx() << "," << s3.gety() << "," << ")";
system("pause");
}
重载函数模板
函数模板本身可以用多种方式重载,还需要提供其他函数模板,指定不同参数的相同函数名。 例:
代码语言:javascript复制#include<iostream>
using namespace std;
template <class T>
void dispArr(T *arr, int n)
{
int i;
for (i = 0; i < n; i )
cout << arr[i] << " ";
cout << endl;
}
template <class T>
void dispArr(T *arr, int i, int j)
{
int k;
for (k = i; k < j; k )
cout << arr[k] << " ";
cout << endl;
}
void main()
{
int a[] = { 1, 2, 4, 6, 8, 5, 3, 5, 8, 2 };
dispArr(a, sizeof(a) / sizeof(a[0]));
dispArr(a, 1, 7);
system("pause");
}
函数调用的匹配
函数模板与同名的非函数模板的重载方法均遵循规定: (1)寻找一个参数完全匹配的函数,如果找到了就调用它。 (2)在(1)失败后,寻找一个函数模板,使其实例化,产生一个匹配的模板函数,若找到了就调用它。 (3)在(1)(2)均失败后,再试试低一级的对函数的重载方法,例如通过类型转换可产生参数匹配,若找到了就调用它。 (4)若以上都失败了,则就是一个错误的调用
代码语言:javascript复制#include<iostream>
using namespace std;
template<class T>
T max(T x, T y)
{
cout << "函数模板max=";
return (x > y) ? x : y;
}
int max(int x, int y, int z = 0)
{
int m;
cout << "int重载函数:max=";
if (z == 0) return (x > y) ? x : y;
else
{
m = (x > y) ? x : y;
return (m > z) ? m : z;
}
}
char max(char x, char y)
{
cout << "char重载函数:max=";
return (x > y) ? x : y;
}
void main()
{
int i1 = 2, i2 = 3, i3 = 5;
char c1 = 'a', c2 = 'c', c3 = 'd';
double f1 = 2.321, f2 = 3.133;
cout << max(i1, i2) << endl;
cout << max(i1, i2, i3) << endl;
cout << max(c1, c2) << endl;
cout << (char)max(c1, c2, c3) << endl;
cout << max(f1, f2) << endl;
system("pause");
}