目录
stack
queue
deque
priority_queue
使用
模拟实现
仿函数
仿函数的用法
仿函数的意义
模板进阶
非类型模板参数
模板特化
类模板特化的用法
类模板特化的意义
函数模板特化的用法
模板的分离编译
模板分离编译报错的原因
解决方法
模板总结
栈、队列和堆的用法在我的<<数据结构>>专栏都已经分享过了,详见以下博客:
别样的数据结构---栈-CSDN博客
别样的数据结构---队列-CSDN博客
独树一帜的完全二叉树---堆-CSDN博客
下面内容的重点还是模拟实现,不过栈和队列以及优先级队列的模拟实现与之前容器的实现有很大区别,我们知道,栈和队列的底层结构可以是顺序表,也可以是链表,只是新增了先进先出还是先进后出的限制,优先级队列的底层本质是堆,存储结构也是顺序表,因此,本篇博客中栈和队列的实现借助其他容器就可以实现!
这也是我们要讲解的栈和队列容器适配器,也就是用其他容器适配栈或者队列,至于哪些容器可以适配,哪些容器不能适配,完全取决于适配的容器有没有提供栈和队列要用到的接口~
stack
namespace dck
{
//通过模板参数,控制底层容器是谁,不管底层容器是谁,都可以适配出后进先出的栈
template <class T, class Container>
class stack
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_back();
}
const T& top()
{
return _con.back();
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
private:
Container _con;
};
}
int main()
{
dck::stack<int, vector<int>> st;
//dck::stack<int, list<int>> st;
//dck::stack<int, deque<int>> st; //deque是双端队列,也是STL容器
st.push(1);
st.push(2);
st.push(3);
st.push(4);
st.push(5);
while (!st.empty())
{
cout << st.top() << " "; // 5 4 3 2 1
st.pop();
}
return 0;
}
queue
using namespace std;
namespace dck
{
template <class T, class Container = deque<T>>
class queue
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_front();
}
const T& front()
{
return _con.front();
}
const T& back()
{
return _con.back();
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
private:
Container _con;
};
}
//vector不能适配queue
//因为vector不支持头删
int main()
{
//dck::queue<int, list<int>> q;
//dck::queue<int, deque<int>> q;
dck::queue<int, vector<int>> q;
q.push(3);
q.push(1);
q.push(2);
q.push(7);
q.push(5);
while (!q.empty())
{
cout << q.front() << " "; //3 1 2 7 5
q.pop();
}
return 0;
}
deque
双端队列也是STL容器之一,库中使用stack与queue都没有传递第二个模板参数,是因为库中的stack与queue默认的容器适配器就是deque
双端队列和队列没有什么关系哦,双端队列并没有先进先出的要求,库中提供的双端队列的接口几乎是vector和 list的综合, 但实际deque并不常用,因为deque在具体的某一方面的效率不如vector或listl, 那为啥还要有deque容器的存在呢??
我们知道vector的优点是尾插尾删效率高,支持下标的随机访问,缺点是中间或者头部的插入删除需要大量挪动数据,而list的优点是随机插入的效率很高,按需申请释放空间,缺点是不支持下标的随机访问,而deque在尾插尾删或者下标随机访问方面必然不如vetor, 在中间或头部的插入删除方面不如list, 但deque综合了两者的优点, 所以deque不是单向冠军,但综合实力很不错~
下面是deque的结构,我们简单说明一下:
中控数组本质是一个指针数组,每个数组元素保存的是一段buff数组的地址,所以插入元素很简单,只需要在buff中插入即可,如果buff满了,那就重新开辟一段buff数组,再保存buff数组的地址到中控数组元素中即可; 当中控数组满了,才需要扩容,而且扩容拷贝数据的代码很低,因为中控数组的元素都是指针,大小都是4/8个字节
如果想在中间插入元素,那就有两种选择:
一是整体挪动所有buff数组的数据,优点是保证每个buff数组是一样大的,[ ]下标的随机访问效率依旧很高,只需要让下标i减去第一个没有满的buff数组的元素个数,再 /= buff数组的大小,就可以定位到第几个buffer, 然后 % buff数组大小,就可以确定在buff数组的第几个位置;缺点是整体挪动数据效率下降!
二是扩容当前要插入的buff数组,优点是不用挪动大量数据,效率比较高,缺点是每个buff数组不一样大,所以[ ] 下标随机访问时候效率低下,需要依次用下标 i 减掉每个buff数组的大小!
priority_queue
priority_queue底层就是学习数据结构时讲到的堆,可以看到,priority_queue也用到了容器适配器---vector, 使用priority_queue不需要单独包头文件,因为priority_queue是放在queue头文件中的!
使用
#include <iostream>
using namespace std;
#include <queue>
void test_priority_queue1()
{
priority_queue<int> q; //默认是大堆(默认是第三个参数是less)
//priority_queue<int, vector<int>, less<int>> q; //less是大堆
q.push(3);
q.push(1);
q.push(5);
q.push(2);
q.push(4);
while (!q.empty())
{
cout << q.top() << " "; //5 4 3 2 1
q.pop();
}
cout << endl;
}
void test_priority_queue2()
{
priority_queue<int, vector<int>, greater<int>> q; //greater是小堆
q.push(3);
q.push(1);
q.push(5);
q.push(2);
q.push(4);
while (!q.empty())
{
cout << q.top() << " "; //1 2 3 4 5
q.pop();
}
cout << endl;
}
void test_priority_queue3()
{
vector<int> v;
v.push_back(3);
v.push_back(1);
v.push_back(4);
v.push_back(2);
priority_queue<int> q(v.begin(), v.end()); //支持用迭代器区间构造
while (!q.empty())
{
cout << q.top() << " "; //4 3 2 1
q.pop();
}
cout << endl;
}
int main()
{
//test_priority_queue1();
//test_priority_queue2();
test_priority_queue3();
return 0;
}
模拟实现
#include <iostream>
#include <vector>
using namespace std;
namespace dck
{
template <class T, class Container = vector<T>>
class priority_queue
{
public:
//无参构造函数
priority_queue()
{}
//构造函数(迭代器区间)
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:_con(first, last)
{
//向下调整建堆
for (int i = (_con.size() - 2) / 2; i >= 0; i--)
{
adjust_down(i);
}
}
//向上调整
void adjust_up(int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (_con[parent] < _con[child])
{
swap(_con[child], _con[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
//插入
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size()-1);
}
//向下调整
void adjust_down(int parent)
{
int child = parent * 2 + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && _con[child] < _con[child + 1])
{
child = child + 1;
}
if (_con[parent] < _con[child])
{
swap(_con[child], _con[parent]);
parent = child;
child = (child * 2) + 1;
}
else
{
break;
}
}
}
//删除堆顶元素
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
private:
Container _con;
};
}
void test_priority_queue1()
{
dck::priority_queue<int> q;
q.push(2);
q.push(3);
q.push(1);
q.push(4);
while (!q.empty())
{
cout << q.top() << " "; //4 3 2 1
q.pop();
}
cout << endl;
}
仿函数
仿函数本质是一个对象,只不过因为对应的类重载了函数调用运算符---(), 所以对象可以像函数一样来使用,所以叫做仿函数
仿函数的用法
template <class T>
class Less
{
public:
bool operator()(T x, T y)
{
return x < y;
}
};
void test_functor()
{
Less<int> less;
cout << less(1, 2) << endl; //1
cout << less(1.5, 0.6) << endl; //0
}
int main()
{
test_functor();
return 0;
}
仿函数的意义
以上述priority_queue模拟实现为例, 我们写的代码实现的是大堆,如果想要变小堆,就需要用到函数指针了,而函数指针比较复杂,所以C++采用了仿函数实现!
无非就是给priority_queue新增了一个模板参数来控制传递的类,进而可以在priority_queue类内部来决定比较时是>还是<, 从而控制了大小堆
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class Less
{
public:
bool operator()(T x, T y)
{
return x < y;
}
};
template <class T>
class Greater
{
public:
bool operator()(T x, T y)
{
return x > y;
}
};
namespace dck
{
template <class T, class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
public:
//无参构造函数
priority_queue()
{}
//构造函数(迭代器区间)
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:_con(first, last)
{
//向下调整建堆
for (int i = (_con.size() - 2) / 2; i >= 0; i--)
{
adjust_down(i);
}
}
//向上调整
void adjust_up(int child)
{
Compare com;
int parent = (child - 1) / 2;
while (child > 0)
{
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
//插入
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size()-1);
}
//向下调整
void adjust_down(int parent)
{
Compare com;
int child = parent * 2 + 1;
while (child < _con.size())
{
//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
child = child + 1;
}
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = (child * 2) + 1;
}
else
{
break;
}
}
}
//删除堆顶元素
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
private:
Container _con;
};
}
有了上面仿函数的实现,我们就可以像库一样通过控制给priority_queue传递的参数来控制大小堆
void test_priority_queue1()
{
dck::priority_queue<int> q; //默认是大堆
q.push(2);
q.push(3);
q.push(1);
q.push(4);
while (!q.empty())
{
cout << q.top() << " "; //4 3 2 1
q.pop();
}
cout << endl;
}
void test_priority_queue2()
{
dck::priority_queue<int, vector<int>, Greater<int>> q; //小堆
q.push(2);
q.push(3);
q.push(1);
q.push(4);
while (!q.empty())
{
cout << q.top() << " "; //1 2 3 4
q.pop();
}
cout << endl;
}
int main()
{
//test_priority_queue1();
test_priority_queue2();
return 0;
}
除了上面的传统比较方法,我们也可以自定义仿函数的比较方法,假设有如下场景:
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class Less
{
public:
bool operator()(T x, T y)
{
return x < y;
}
};
template <class T>
class Greater
{
public:
bool operator()(T x, T y)
{
return x > y;
}
};
namespace dck
{
template <class T, class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
public:
//无参构造函数
priority_queue()
{}
//构造函数(迭代器区间)
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:_con(first, last)
{
//向下调整建堆
for (int i = (_con.size() - 2) / 2; i >= 0; i--)
{
adjust_down(i);
}
}
//向上调整
void adjust_up(int child)
{
Compare com;
int parent = (child - 1) / 2;
while (child > 0)
{
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
//插入
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size()-1);
}
//向下调整
void adjust_down(int parent)
{
Compare com;
int child = parent * 2 + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
child = child + 1;
}
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = (child * 2) + 1;
}
else
{
break;
}
}
}
//删除堆顶元素
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
private:
Container _con;
};
}
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
bool operator<(const Date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const Date& d)const
{
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
friend ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
void test_priority_queue3()
{
dck::priority_queue<Date> q1;
q1.push(Date(2018, 10, 29));
q1.push(Date(2018, 10, 28));
q1.push(Date(2018, 10, 30));
cout << q1.top() << endl; //2018-10-30
dck::priority_queue<Date*> q2;
q2.push(new Date(2018, 10, 29));
q2.push(new Date(2018, 10, 28));
q2.push(new Date(2018, 10, 30));
cout << *(q2.top()) << endl; //每次打印结果都在变化
}
int main()
{
test_priority_queue3();
return 0;
}
由于优先级队列中我们传参传的是指针,new出来的空间地址是随机的,所以比较结果一直在变化,虽然传递的是就是指针,但是如果我们就是想按照Date的大小来比较呢??所以我们就可以自己写一个仿函数,定义新的比较规则, 这样就可以按照我们想要的方式去比较了~
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class Less
{
public:
bool operator()(T x, T y)
{
return x < y;
}
};
template <class T>
class Greater
{
public:
bool operator()(T x, T y)
{
return x > y;
}
};
namespace dck
{
template <class T, class Container = vector<T>, class Compare = Less<T>>
class priority_queue
{
public:
//无参构造函数
priority_queue()
{}
//构造函数(迭代器区间)
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:_con(first, last)
{
//向下调整建堆
for (int i = (_con.size() - 2) / 2; i >= 0; i--)
{
adjust_down(i);
}
}
//向上调整
void adjust_up(int child)
{
Compare com;
int parent = (child - 1) / 2;
while (child > 0)
{
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
//插入
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size()-1);
}
//向下调整
void adjust_down(int parent)
{
Compare com;
int child = parent * 2 + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
child = child + 1;
}
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = (child * 2) + 1;
}
else
{
break;
}
}
}
//删除堆顶元素
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
private:
Container _con;
};
}
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
bool operator<(const Date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const Date& d)const
{
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
friend ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
class PDateCompare
{
public:
bool operator()(Date* x, Date* y)
{
return *x < *y;
}
};
void test_priority_queue3()
{
dck::priority_queue<Date> q1;
q1.push(Date(2018, 10, 29));
q1.push(Date(2018, 10, 28));
q1.push(Date(2018, 10, 30));
cout << q1.top() << endl; //2018-10-30
dck::priority_queue<Date*, vector<Date*>, PDateCompare> q2;
q2.push(new Date(2018, 10, 29));
q2.push(new Date(2018, 10, 28));
q2.push(new Date(2018, 10, 30));
cout << *(q2.top()) << endl; //2018-10-30
}
int main()
{
test_priority_queue3();
return 0;
}
模板进阶
非类型模板参数
我们定义了一个栈类型,栈的成员变量---数组的大小是固定的,现在定义了两个栈对象,一个栈想开辟10大小的空间,另一个栈想开辟100大小的空间,此时我们就可以用到非类型的模板参数
#include <iostream>
using namespace std;
template <class T, size_t N> //非模板参数必须是整形家族的(整形,字符型),不能是浮点型等其他类型
class Stack
{
private:
T _a[N];
};
int main()
{
Stack<int, 10> st1;
Stack<int, 100> st2;
int n;
cin >> n;
//Stack<int, n> st3; //err, 非模板参数必须传常量
return 0;
}
非类型的模板参数还是有存在的意义的,比如C++11新出的容器array以及位图bitset都用到了非类型的模板参数
#include <array>
int main()
{
int arr1[10];
array<int, 10> arr2;
cout << sizeof(arr1) << endl; //10
cout << sizeof(arr2) << endl; //10
//arr1[20] = 1; //编译器对静态数组的越界是一种抽查,所以即使越界,程序也可能正常运行
arr2[20] = 1; //转化成去调用运算符重载函数, 越界直接assert断言报错, 检查更为严格
return 0;
}
模板特化
模板特化指的是指对某些类型进行特殊处理, 类模板实例化时也就采用最匹配原则!
注意, 特化模板不能单独存在,必须先有原模板,才能有特化模板
类模板特化的用法
全特化
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//下面这个类叫做上面类的全特化
template<>
class Data<int, double>
{
public:
Data() { cout << "Data<int, double>" << endl; }
private:
int _d1;
double _d2;
};
int main()
{
Data<int, int> d1; //Data<T1, T2>
Data<int, double> d2; //Data<int, double>
return 0;
}
偏特化类型一:
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//下面这个类叫做上面类的偏特化
template<class T>
class Data<T, double>
{
public:
Data() { cout << "Data<T, double>" << endl; }
private:
T _d1;
double _d2;
};
int main()
{
Data<int, int> d1; //Data<T1, T2>
Data<double, double> d2; //Data<T, double>
return 0;
}
偏特化类型二:
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//下面这个类叫做上面类的偏特化
template<class T1, class T2>
class Data<T1*, T2*> //只要是两个指针类型,就实例化我这个模板
{
public:
Data() { cout << "Data<T1*, T2*>" << endl; }
private:
T1* _d1;
T2* _d2;
};
int main()
{
Data<int, int> d1; //Data<T1, T2>
Data<double*, int*> d2; //Data<T1*, T2*>
return 0;
}
类模板特化的意义
上文在讲解priority_queue时,如果传递的参数是Date*,但是还是想按照Date内容进行比较,这时除了自己写一个PDateCompare仿函数之外,还可以将Less模板进行全特化
template <class T>
class Less
{
public:
bool operator()(T x, T y)
{
return x < y;
}
};
//模板全特化
template <>
class Less<Date*>
{
public:
bool operator()(Date* x, Date* y)
{
return *x < *y;
}
};
同样的,我们也可以利用偏特化类型二解决上述问题
template <class T>
class Less
{
public:
bool operator()(T x, T y)
{
return x < y;
}
};
//模板偏特化
template <class T>
class Less<T*>
{
public:
bool operator()(T* x, T* y)
{
return *x < *y;
}
};
函数模板特化的用法
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
bool operator<(const Date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator>(const Date& d)const
{
return (_year > d._year) ||
(_year == d._year && _month > d._month) ||
(_year == d._year && _month == d._month && _day > d._day);
}
friend ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
//函数模板
template <class T>
bool Less(T left, T right)
{
return left < right;
}
//函数模板特化
template <>
bool Less<Date*>(Date* left, Date* right)
{
return *left < *right;
}
int main()
{
Date* d1 = new Date(2023, 10, 8);
Date* d2 = new Date(2023, 10, 9);
cout << Less(d1, d2) << endl; //1
return 0;
}
类模板推荐使用特化,但函数模板不推荐采用特化,容易出问题, 比如下面这段代码
//函数模板
template <class T>
bool Less(const T& left, const T& right) //为了提高传参效率,采用引用
{
return left < right;
}
//函数模板特化
template <>
//下面这种写法是错误的,因为期望const修饰的是引用,但是直接把T替换成Date*之后,const修饰的是指针
//bool Less<Date*>(const Date* &left, const Date* &right) //×
bool Less<Date*>(Date* const &left, Date* const &right) //√
{
return *left < *right;
}
所以函数模板尽量不要用特化,可以写一个具体的函数,来和函数模板实例化生成的具体函数构成重载即可
//函数模板
template <class T>
bool Less(const T& left, const T& right)
{
return left < right;
}
//具体函数
bool Less(Date* left, Date* right)
{
return *left < *right;
}
模板的分离编译
模板分离编译报错的原因
解决方法
1.显式实例化
函数模板显式实例化
a.cpp
template <class T>
T Add(const T& left, const T& right)
{
return left + right;
}
//显示实例化成int
template
int Add<int>(const int& left, const int& right);
//显示实例化成double
template
double Add<double>(const double& left, const double& right);
类模板显式实例化
a.cpp
template<class T>
void Stack<T>::Push(const T& x)
{
cout << "void Stack<T>::Push(const T& x)" << endl;
}
template<class T>
void Stack<T>::Pop()
{
cout << "void Stack<T>::Pop()" << endl;
}
//显式实例化
template
class Stack<int>;
2.模板声明和定义写在同一个文件中
比如我们把模板的声明和定义都写在a.h中,就没有问题了~
a.h / a.hpp
.hpp的一般指的是我这个文件既有声明,也有定义,大概率是含有模板,不方便分离编译~
#include <iostream>
using namespace std;
//函数模板声明
template<class T>
T Add(const T& left, const T& right);
//函数模板定义
template <class T>
T Add(const T& left, const T& right)
{
return left + right;
}
//类模板声明
template<class T>
class Stack
{
public:
void Push(const T& x);
void Pop();
private:
T _a;
int _top;
int _capacity;
};
//类模板定义
template<class T>
void Stack<T>::Push(const T& x)
{
cout << "void Stack<T>::Push(const T& x)" << endl;
}
template<class T>
void Stack<T>::Pop()
{
cout << "void Stack<T>::Pop()" << endl;
}
模板总结
【优点】1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生2. 增强了代码的灵活性【缺陷】1. 模板会导致代码膨胀问题,也会导致编译时间变长2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误