c++系列模板入门
文章目录
- c++系列模板入门
- 一、模板概念引入
- 二、函数模板
- 2.1、函数模板的概念
- 2.2、函数模板的定义格式
- 2.3、函数模板的使用
- 三、类模板
- 1.1、什么是类模板
- 1.2、类模板的定义格式
- 1.3、类模板于函数模板的区别
一、模板概念引入
在程序设计中我们经常需要对两个数据进行交换,对于不同的数据类型,我们就需要重载不的函数。
void Swap(int& left, int& right){int temp = left;left = right;right = temp;}
void Swap(double& left, double& right){double temp = left;left = right;right = temp;}
问:面对这些逻辑相同,仅是类型不同的程序,我们该如何更好的实现他们呢?
答:如果有一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(生成具体类型的代码),那我们将会方便很多,为完成这一问题C++产生了泛型编程的思想。
泛型编程:允许函数和数据结构使用任何数据类型,而不需要为每种数据类型编写重复的代码。模板是泛型编程的基础。
模板——是一段带有类型参数的程序代码,可以通过给这些参数提供一些类型来得到针对不同类型的具体代码。
二、函数模板
2.1、函数模板的概念
函数模板并不是一个可以直接使用的函数,它实际上是定义一个通用函数,它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)均被作为参数:不指定具体类型,而是用一个虚拟 的类型来代替(实际上是用一个标识符来占位)。凡是函数体相同的函数都可以用这个模板来代替,在函数调用时根据传入的实参来逆推出真正的类型(逆推过程由编译器来完成),从而来实现代码的复用。这个通用函数就称为函数模板(函数模板不是一个实在的函数,编译器不能为其生成可执行代码)。
2.2、函数模板的定义格式
template<class / typename T1,......,class / typename Tn> typename用来定义模板参数关键字,也可以使用class,在这里他们两个的作用并无区别,T1....Tn均为类型占位符。
template<typename T>//简单函数模板void Swap( T& left, T& right){T temp = left;left = right;right = temp;}
2.3、函数模板的使用
以两数相加函数为例,我们在进行不同类型对象间的数据相加问题时,就不需要重写多个函数 例:
template<class T1>
T1 add(T1 x,T1 y)//T1类型占位符,编译器推演出合适的类型将他替换
{return x + y;
}
int main()
{int a1 = 1;int a2 = 2;double a3 = 1.1;double a4 = 2.1;cout << add(a1, a2) << endl;cout << add(a3, a4) << endl;return 0;
运行结果:
在使用函数模板时,我们只需要传递实参,编译器会自动推演出合适的类型。
可以看到,即使存在模板还是可以定义,具体的函数的,编译器在生成函数之前,首先会去,局部、全局找是否有合适的函数,如果有则调用已存在的,否则生成函数(这里double类型就没有合适的,所以调用生成函数)。
通过上面两张图我们可看到,我将模板屏蔽后代码是可以执行的,这是因为,我们自己定义的函数,支持隐式类型转换(从打印结果可以看到,从在数据丢失问题),当我们,将自定义函数屏蔽后,成序出错,这是因为,我们只声明了一个类型占位符,编译不知道将他推演成什么类型(间接反映出,编译器生成的函数,不支持隐式类型转换)。
对于这个问题,我们有三种方法解决:
1.在传递实参时,进行显示类型转换
cout << add(a1,(int) a4) << endl;
2.在原模板上,增加一个模板参数
template<class T1,class T2>
T1 add(T1 x,T2 y){}//这里函数体省略了
3.模板显示实例化
cout << add<int>(a1, a4) << endl;
具体改变大家可以用代码跑一下
三、类模板
1.1、什么是类模板
类模板是一种用来生成类定义的模板,其中可以包含一个或多个类型参数。这些类型参数可以在定义类的时候替换为任意类型,从而使得我们能够创建适用于多种数据类型的通用类定义。类模板的定义使用 template < class T> 或 template< typename T> 来声明一个类型参数(可以声明多个)。
1.2、类模板的定义格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{// 类内成员定义
};
我们以这个简单的线性表为例,进行讲解
template<class T>
class Vector
{
public:Vector(size_t capacity = 10): _pData(new T[capacity]),_size(0),_capacity(capacity){}// 使用析构函数演示:在类中声明,在类外定义。~Vector();void PushBack(const T& data);void PopBack();size_t Size() { return _size; }T& operator[](size_t pos){assert(pos < _size);return _pData[pos];}
private:T* _pData;size_t _size;size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{if (_pData)delete[] _pData;_size = _capacity = 0;
}
在对类模板进行定义时,类的成员函数一样可以使用,模板参数精选模板定义。
1.3、类模板于函数模板的区别
类模板不同于函数模板,它没有自动类型推导的使用方式,类模板在使用时,只能使用显示定义的方式 例:
//使用类模板创建对象Vector<int> v1;vector<double> v2;
这里我们要知道,类名(vector)并不是所创建对象的类型,只有对象被实力出来,它才具有类型(vector< int>、vector< double>).
类模板可以有,默认参数类型例:
template<class T1, class T2, ..., class Tn=int>//默认参数类型
class 类模板名
{// 类内成员定义
};
这里同定义函数时,使用缺省参数,原理相同。