前言
在我们的日常编程当中,经常使用同一种类型的函数或者类,我们之前采用的方法是函数的重载,但是函数重载仅仅只是类型的不同,代码复用率低,只要有新的类型增加,就需要增加对应的函数;其次,代码的可维护性比较低,一个出错可能所有的重载均出错。为此,我们引入了模板。
一、函数模板
1、函数模板的概念:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数特定类型版本。
2、函数模板的格式
template<typename T1,typename T2,.......typename n>
返回值类型 函数名(参数列表){}
template<typename Myclass1,typename Myclass2>
void fun(Myclass1 &t1, Myclass2 &t2)
{
Myclass tmp = t1;
t1 = t2;
t2 = tmp;
}
3、函数模板的原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的事情交给了编译器。
在编译器编译阶段,对于模板函数的作用,编译器需要根据传入的实参类型来推演生成对应类型的函数以提供调用。
4、函数模板的实例化
用不同类型的参数使用函数模板时,称之为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
#include<iostream>
using namespace std;
class Myclass
{
public:
template<typename T>
T fun(const T &t1, const T &t2)
{
return t1 + t2;
}
private:
int m_data;
};
int main()
{
Myclass X1;
Myclass X2;
X1.fun(10, (int)10.2); //隐式转换
X2.fun<int>(10, 10.2); //显示转换
return 0;
}
5、模板参数的匹配原则
5.1、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
5.2、对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。
5.3、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
二、类模板
1、定义格式
template<class T1,class T2,......class Tn>
class 类模板名
{
//类内定义成员
};
2、类模板的实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后面跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
template<typename Type, size_t _N=8> //非类型模板参数
class SeqList
{
public:
SeqList(int sz = _N)
{
capacity = sz > _N ? sz : _N;
base = new Type[capacity];
size = 0;
}
~SeqList()
{
delete []base;
base = nullptr;
capacity = size = 0;
}
public:
void push_back(const Type &v);
private:
Type *base;
size_t capacity;
size_t size;
};
void main()
{
SeqList<int, 20> mylist;
SeqList<int, 200> mylist1;
SeqList<char, 10> youlist(1);
SeqList<string, 8> hilist;
}
三、非类型模板参数,零初始化,模板的分离编译
1、非类型模板参数如上面代码所示
2、零初始化
template<typename Type>
class Test
{
public:
//零初始化
Test(Type data=Type()) : m_data(data)
{}
private:
Type m_data;
};
void main()
{
Test<int> t;
Test<bool> t1;
}
3、模板的分离编译
C++不支持模板的分离编译,也就是说不支持函数的申明在一个文件当中而实现在另外一个文件当中。
更多推荐
C++的函数模板和类模板
发布评论