首先给出一个栈的类
class Stack
{
public:
Stack(size_t capacity = 4)//不传入值则就默认4个空间,(构造函数)
{
cout << "Stack(size_t n = 4)" << endl;
_a = new DataType[capacity];
_capacity = capacity;
_top = 0;
}
~Stack()
{
cout << "~Stack()" << endl;
delete[] _a;
_a = nullptr;
_top = _capacity = 0;
}
void Push(int x)
{
if (_top == _capacity)
{
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
int* tmp = (int*)realloc(_a, sizeof(int) * newcapacity);
if (tmp == nullptr)
{
perror("realloc fail");
exit(-1);
}
if (tmp = _a)
{
cout << _capacity << "原地扩容" << endl;//原地扩容还是异地扩容呢?
//若打印就原地,否则就异地
}
else
{
cout << _capacity << "异地扩容" << endl;
}
_a = tmp;
_capacity = newcapacity;
}
_a[_top++] = x;
}
private:
//内置类型
int* _a;
size_t _top;
size_t _capacity;
};
现在,我们由这个代码,知道这个栈里的元素都是整型类型,但是若想实现浮点数double类型呢?
想在一个文件里同时实现不同类型的栈怎么办?——此时就需要用模板
什么是模板?
模板——可以作为一个模具,实现的内容基本一致,不同的是数据的类型
函数模板
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
格式
template<class T>
template<typename T>
template<typename T1, typename T2.......,typename TN>
//calss 和 typename均可以使用
返回值类型 函数名(参数列表){}
示例
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;
}
void Swap(char& left, char& right)
{
char temp = left;
left = right;
right = temp;
}
对于交换函数,我们往往会写多个重载函数进行不同类型数据之间的交换,但是这样会让代码比较麻烦,那么如何用模板简化呢?
template<typename T>//模板,类型会自由转换
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
每次使用模板前需要对模板的参数进行重定义,且调用的函数里的参数必须是同类型,不然就会报错
原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模 板就是将本来应该我们做的重复的事情交给了编译器
实例化
若是输入的两个数据不为同一个类型时呢?现用相加函数来解释:
template<class T>
T Add(const T& x,const T& y)
{
return x+y;
}
1.手动强制类型转换
int main()
{
cout<<Add(1,(int)1.1);
cout<<Add((double)1,1.1);
return 0;
}
2.显示实例化——作用于返回的结果,将类型统一
cout<<Add<int>(1,2.2)<<endl;
cout<<Add<double>(1,2.2)<<endl;
类模板
定义格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
知道定义的格式后,可以对开头提及的栈进行修改
template<class T>
class Stack
{
public:
{}
private:
//内置类型
T* _a;
size_t _top;
size_t _capacity;
};
此时,便可以实现不同类型的栈
类模板实现顺序表
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);
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()
{
delete[] _pData;
_pData = nullptr;
}
类模板中函数放在类外进行定义时,需要加模板参数列表
类模板的实例化
Vector<int> s1;
Vector<double> s2;
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
Vector类名,Vector<T>才是类型