如果说C++和C区别,我认为有两个最大的改进;其一是实现了类的封装,还有一个就是实现了多种相同动作的重载,今天我们提到的就是模板,小编认为其也是属于重载的一部分,模板相当于重新定义了个模具让不同的对象产生类似的行为,和重载区别不同的就是,模板是一个模板可以让多个对象进行类似的动作,重载则是可以让不同的对象进行不同的动作。
首先来看下模板的分类:
我们首先来看一下函数模板:
函数模板无疑就是由函数构成的模板
学习的时候,你可能会想,为什么要用模板?我C语言可以宏定义,可以设计函数,C++还可以重载函数?这些不香吗?我非要再整个语法。我们来看个例子就发现。
for example:
交换两个数
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
我们很轻松就写出了这个例子,但是我们很快就发现这个完美,瑕疵很多,于是乎我们就想到了C++的重载:
void swap(float *a, float *b)
{
float temp = *a;
*a = *b;
*b = temp;
}
我们继续想,如果让一个整形数和一个浮点数进行比较的话怎么整?在实际应用中这个也经常出现啊?继续重载。。。我们发现,真的是很烦,写了好多函数,实际上就是将形参的类型改变了,实际上很多代码还是没有改变的,有没有一个方法能够让这个代码一下子简介起来了?
这就需要用到我们的第一个,函数模板。
语法:
template
T是函数模板中的通用类型,在使用的时候被实例化。这个template是关键字。typename是类型名称
有啥好处呢?
- 函数模板定义了一套适用于各种数据类型的一般操作;
- 函数模板可以不依赖与=于任何数据类型来定义算法的属性。
其调用方式有2种。
隐式调用:
允许将抽象的函数模板显式的声明为某个具体的模板函数这个中间步骤,而直接用值调用函数模板,编译将根据值的类型自动地实例化模板函数。
直接上代码:
template <class T>
void Swap(T& a,T&b)
{
T temp = a;
a = b;
b = temp;
}
我们来看实际应用时这个操作的强度
int main()
{
int i = 5;
int j = 6;
Swap(i, j);
cout << i << j;
char a = 'C';
char b = 'J';
Swap(a, b);
cout << a << b;
system("pause");
return 0;
}
很方便,直接调,这就是所谓的隐式调用。
再来看显式调用,隐式调用就是没说这个类型是啥模板自动识别出来了类型,显示调用正好相反,显式调用需要先声明类型是啥,直接根据数据类型调用相应的模板 。实际上就是将模板实例化,我们来看一组对比的代码就清晰了。
通过这张图我们可以清楚看到,我们可以轻易的实现相同类型的操作,因为我们传递参数的时候都是T累型,但是如果参数类型 不一致了,编译器就想,到底是将 T1类型强制抓换成T2还是将T2类型强制转换成T1呢?这就需要我们用户来处理。
解决办法有两个
- 将类型不一致的手动强制转换成类型一致的;
- 显示调用。
template<class T>
T Add(const T& left, const T&right)
{
return left + right;
}
int main()
{
int a = 5;
int b = 6;
cout<<Add(a, b) << endl;
double c = 2.8525;
double d = 6.2;
cout << Add(c, d) << endl;
cout << Add(a, (int)c) << endl;//方案一,强转
cout<<Add<double>(a, c)<<endl;//显式调用
system("pause");
return 0;
}
接下来我们来看看模板匹配原则
- 模板函数时可以和非模板函数重名的,非模板函数还可以是模板函数的实例化成员;
- 当重名的模板函数和非模板函数在一起时默认调用的是非模板函数而不会从模板函数中实例化一个出来调用;
- 模板函数不允许自动类型强制转换。
我们接下来看看类模板
有了函数模板的基础,类模板就有了很好的铺垫,类比模板函数,类模板就是说明这个类是模板,一个类应该具有哪些东西呢?来瞅代码。
template<class T>
class Vector
{
private:
T* p_data;
size_t size;
size_t capacity;
public:
Vector(size_t capacity = 10) : _pData(new T[capacity]), size(0), capacity(_capacity)
{}
~Vector();
void pushbank(T &data);
void popbank(T &data);
};
//注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{ if (_pData)
delete[] _pData;
_size = _capacity = 0;
}
int main()
{
Vector<int>s1;
Vector<double>s2;
system("pause");
return 0;
}
需要注意,模板类的名字不是真正的类,实例化的成员名字才是模板类。