前面我们学到了函数重载这个特性,对于交换函数,可能要写int和int类型的交换,可能要写double和double类型的交换,还可能写char和char类型的交换,这样就有不好之处:
那么能否告诉编译器一个模板让编译器根据不同类型利用该模板来生成代码呢?那么这里就需要用到C++模板。
泛型编程就是编写与类型无关的通用代码,是代码复用的一种手段。
template
template
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
typename是用来定义模板参数的关键字,也可以用class。
函数模板就是一个蓝图,本身并不是函数,是编译器用来产生特定具体类型函数的模具而已,把重复的事交给了编译器做。
编译器编译阶段,编译器需要根据传入的实参类型来推演出对应的类型函数以供调用
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化
template
T Add(const T& e1, const T& e2) //隐式实例化:让编译器根据实参推演参数的实际类型
{
return e1 + e2;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.1, d2 = 20.1;
cout << Add(a1, a2) << endl; //两个实参类型都是int
cout << Add(d1, d2) << endl; //两个实参类型都是double
//cout << Add(a1, d1) << endl; //error,一个实参是int,一个实参是double
//怎么来解决这里的错误呢?
//1.手动强制转化
cout << Add(a1, (int)d1) << endl;
cout << Add((double)a1, d1) << endl;
//2.使用显示实例化(显示实例化:在函数名后的<>中指定模板参数的实际类型)
cout << Add(a1, d1) << endl;
cout << Add(a1, d1) << endl;
//3.增加一个模板参数
//template --> template
return 0;
}
int Add(int left, int right)
{
return left + right;
}
template
T Add(T left, T right)
{
return left + right;
}
void Test()
{
Add(1, 2); // 调用非模板
Add(1, 2); // 调用模板
}
int Add(int left, int right)
{
return left + right;
}
template
T1 Add(T1 left, T2 right)
{
return left + right;
}
void Test()
{
Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}
template
class 类模板名
{
// 类内成员定义
};
//栈
typedef int stackType;
class stack
{
private:
int* _a;
int _top;
int _capacity;
};
int main()
{
stack s1;
stack s2;
//一个typedef可以让s1这个栈存放int类型的,s2这个栈存放double类型的吗? 不能,所以就要用到类模板
return 0;
}
改进
template
class stack
{
private:
T* _a;
int _top;
int _capacity;
};
int main()
{
stack s1; //类模板只能显示实例化
stack s2;
return 0;
}
注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template
class stack
{
public:
stack(int capacity = 4)
{
_a = new T[capacity];
_top = -1;
_capacity = capacity;
}
~stack();
private:
T* _a;
int _top;
int _capacity;
};
template
stack::~stack() //类模板中函数放在类外进行定义时,需要加模板参数列表
{
if (stack::_a != nullptr) {
delete[] _a;
_top = -1;
_capacity = 0;
}
}
类模板实例化与函数模板实例化不同,类模板实例化必需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类,另外vector< int > v中vector是类名,vector< int >才是对象v的类型。