Open bosthhe1 opened 1 year ago
以上图为例,在我们以前的编写中,如果需要交换不同类型的值,就需要写多个函数重载函数,然后一 一对应,但是我们有了泛型函数,就可以直接传值过去,类型会自动推导(有点像auto),泛型函数的书写格式为template<class T,class TP.......>,这里面可以只定义一个,也可以定义多个,看情况而定,值得注意的是,泛型的实例化对于不同的类型,会创建不同类型的函数,所以泛型函数或者类会造成大量的函数膨胀
类型可以编译器推到,也可以指定类型传参
我们这里虽然传参为double类型,但是可以指定传int类型(显示实例化),书写形式为Add
但是我们可以看到在传引用的过程中,是不可以指定其他类型的,只能指定合法的类型,这里是指定调用,确认类型,不可进行隐式类型转换
如果我们推导的参数类型,在定义中已经存在,那么就会去调用已经定义过的函数,而不进行函数推导,当我们已经定义了一个int类型的函数,template推导也为int,系统就会调用已经定义的函数,而不去调用自动推导
template<class T>//类模板(类模板和class Stack是一个类整体,相当于连体的)
//template和class中间不允许写其他东西,因为他们是一个整体,不能分开,中间写了其他东西,class会找不到类模板
class Stack
{
public:
Stack(int capacity = 4)
:_top(0)
, _capacity(capacity)
{
_a = new T[capacity];
}
~Stack()
{
delete[] _a;
_a = nullptr;
_top = 0;
}
void Push_Back(T a);
private:
T *_a;
int _top;
int _capacity;
};
//这里相当于出了类,跳到了全局,所以需要重新指定,和class一样,中间不能写其他的东西,必须连着写
template<class T>//这里的模板就是为了指定类
void Stack<T>::Push_Back(T a)//这个需要注意函数定义的方式,不仅要指定类域,也要指定模板,这个函数和上面的模板为一体
{
//..........
}
template<class T>//这里需要重新指定类模板,因为上面函数把这个函数隔开了,这个函数
void Stack<T>::Push_Head(T a)//这个也需要指定类型,同时指定类模板,他们为一体
{
//....
}
int main()
{
Stack<int> d1(4);// 必须手动实例化类模板(因为这里不存在实参传给形参的场景)
return 0;
}
类模板是一个类家族,模板类是通过类模板实例化的具体类
在我们编译写代码的途中,会存在很多的场景,只是需要更换类型,不更换内部结构,如果拷贝复制的话会很麻烦,所以产生了泛型编程,泛型编程相当于一个模板,我们需要什么类型,就将泛型函数或者类,初始化成什么类型,(这里可以不用实例化,这里拥有传参的场景,可以自动推演)