前言
打怪升级:第40天 |
|
|
在c++的开始阶段我们了解到了函数重载,函数重载可以允许我们使用同名函数,方便我们编写那些功能类似但参数不同的函数,例如:
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
void Swap(double& x, double& y)
{
double tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 10, b = 20;
cout << "a = " << a << ", b = " << b << endl;
Swap(a, b);
cout << "a = " << a << ", b = " << b << endl;
double c = 10.11, d = 20.22;
cout << "c = " << c << ", d = " << d << endl;
Swap(c, d);
cout << "c = " << c << ", d = " << d << endl;
return 0;
}
因此,我们祖师爷就在想,能不能我们只自己写一个“模具”出来,之后具体需要什么类型由编译器来判断并且复刻出可以使用的函数?
就像我们的印刷机 – 有一个原样,想要得到它的复制品就轻而易举,这样不仅帮助程序员们节省了对类似代码的拷贝与维护,并且还可以少掉许多头发。
一、泛式编程
泛式编程:编写与类型无关的函数,是代码复用的一种手段,模板是泛式编程的基础。
函数模板
函数模板代表一个函数家族,与类型无关,在使用时根据参数类型实例化出可执行函数(这些都是编译器做的)。
- 函数模板
template<typename T1, tempname T2, …tempname Tn>
返回值 函数名 (T1 data1, T2 data2 …)
{ }
// template<typename T>
// template<typename Type> ... 这个类型名怎么写都可以
template<typename T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 10, b = 20;
cout << "a = " << a << ", b = " << b << endl;
Swap(a, b);
cout << "a = " << a << ", b = " << b << endl;
double c = 10.11, d = 20.22;
cout << "c = " << c << ", d = " << d << endl;
Swap(c, d);
cout << "c = " << c << ", d = " << d << endl;
return 0;
}
类模板
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
template<class T> // 该模板:T 可以在整个类中使用
class A
{
public:
A(int d)
:_d(d)
{
cout << "A" << endl;
}
void Print(T val)
{
cout << val << " " << _d << endl;
}
~A()
{
cout << "~A" << endl;
}
private:
T _d;
};
int main()
{
A<int> a(20);
a.Print(5);
return 0;
}
template<class T>
class A
{
public:
A(int d)
:_d(d)
{
cout << "A" << endl;
}
void Print(T val); // 类外声明
~A()
{
cout << "~A" << endl;
}
private:
T _d;
};
template<class T> // 类模板的成员函数在类外声明需要加 模板参数列表
void A<T>::Print(T val)
{
cout << val << " " << _d << endl;
}
int main()
{
A<int> a(20);
a.Print(5);
return 0;
}
模板这方面在我们c++中可谓非常之重要,了解c++的朋友应该都听说过stl的鼎鼎大名,stl全称为Standard Template Library(标准模板库),
它里面的vector,set以及string等等都是类模板,其中string比较特殊:数据类型只能是char,因此 设计stl 的大佬直接在库中进行了声明:
所以我们在使用string模板时不需要写出模板类型,例如:string<char> str;
而是可以直接使用 string str;
不过其他类模板使用之前就需要声明类型了,例如:
vector<int> array;
vector<double> array;
set<int>s;
等等。
总结
-
模板函数不允许自动类型转换,但普通函数可以进行自动类型转换,例如上面的add模板,两个参数类型需要保持相同;
- 声明一个模板只能够在下方的那一个函数或者类中使用,在其他地方编译器无法识别 , 换句话说就是:每次使用模板都需要进行声明;
- 函数模板的模板类型可以交给编译器自行推导也可以显示声明,而类模板必须显示声明类型;
- 类模板实例化与函数模板实例化不同,类模板实例化需要显示声明模板类型,类模板名字不是真正的类,实例化的结果才是真正的类。