引言:在C语言当中,如果我们想要实现一个能计算整数和浮点数的计算器时,我们都需要根据不同的返回类型和参数类型创建许多个形式极其相似的函数,非常的麻烦,而在C++中,我们将会引入模版的知识概念,这个问题就会迎刃而解了!
更多有关C语言,数据结构和C++的知识详解可前往个人主页:计信猫
一,函数模板
1,概念
函数模板是一个大家族,它与类型无关,在使用时被参数化,会根据参数的类型自动生成对应的函数。
2,格式
格式:
template <class 类型名1,class 类型名2…>
当然此时class也可以用typename来代替,两者的效果是一样的。所以有了以上的知识支持,那么我们就尝试来写一下我们的计算器模板吧!
//T表示参数的类型,会根据传的参数而改变
template <class T>
T ADD(const T& a, const T& b)
{
return a + b;
}
此时该模板会根据函数的参数来进行对模板函数的实例化。
3,实例化
Ⅰ,隐式实例化
隐式实例化非常的简单,就是上边我们所讲的例子,让编译器根据实参的类型来确定模板参数的实际类型。
Ⅱ,显式实例化
让我们来看下面一个例子:
template <class T>
T ADD(const T& a, const T& b)
{
return a + b;
}
int main()
{
int a = 1;
double b = 2.1;
ADD(a, b);
return 0;
}
此时,编译器就会报出错误,因为无法识别T的类型为int,还是double,此时我们就需要用到显式实例化:
法一:ADD<int>(a,b)——>此时两个类型的变量都被强转为int
法二:ADD(a,(int)b)——>此时只有b的类型被转换为int
4,匹配原则
函数模板在使用时遵循着以下几点原则:
1,一个非模板函数可以和一个同名函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
2,对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数。若该模板可以产生一个具有更好匹配的函数,那么将选择模板。
template <class T1,class T2>
T2 ADD(const T1& a, const T2& b)
{
return a + b;
}
int ADD(const int& a, const int& b)
{
return a + b;
}
int main()
{
int a1 = 1;
int a2 = 1;
double b = 2.1;
ADD(a1, a2);//此时就会调用非模板函数
ADD(a1, b);//此时就会调用模板函数
return 0;
}
3,模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
二,类模板
1,格式
在我们前边学习了函数模板的格式之后,其实类模板我们也可以举一反三了。如下,我们就使用模板定义一个栈:
template<class T>
class Stack
{
public:
//构造函数
Stack(int top,int capacity)
:_a(new T[4])
,__top(top)
,_capacity(capacity)
{}
//拷贝构造函数
Stack(const stack& s1)
{
_a = new T[s1._capacity];
memcpy(_a, s1._a, sizeof(T) * s1._top);
_top = s1._top;
_capacity = s1._capacity;
}
//析构函数
~Stack()
{
delete[] _a;
_a = NULL;
_top = _capacity = 0;
}
private:
T* _a;
int _top = 0;
int _capacity = 4;
};
2,实例化
类模板的实例化和函数模板的实例化不同。类模板实例化需要在类模板名字之后跟上<>, 然后将实例化的类型放在<>中即可。类模板名字不是真正的类,而实例化的结果才是真正的类。
//Stack是类名,Stack<int>是类型
Stack<int>st1;
Stack<double>st2;