适配器
概述
适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
用适配器配出栈和队列
用顺序表和链表适配出栈和队列。
用适配器适配出栈
template <class T,class Container> //普通模板参数
class Stack
{
public:
void StackPush(const T& s){_con.PushBack(s);} //入栈
void StackPop(){_con.PopBack();}//出栈
T& StackTop(){return _con.Back();}//取得栈顶元素
bool StackEmpty(){return _con.Empty();}//判断栈是否为空
protected:
Container _con; //普通模板参数
};
测试
void StackTest()
{
Stack<int,Vector<int>> s;
s.StackPush(1);
s.StackPush(2);
s.StackPush(3);
s.StackPush(4);
s.StackPush(5);
while (!s.StackEmpty())
{
cout<<s.StackTop()<<" ";
s.StackPop();
}
cout<<endl;
Stack<string,List<string>> s1;
s1.StackPush("hello");
s1.StackPush("world");
s1.StackPush("welcome");
s1.StackPush("you");
s1.StackPush("!");
while (!s1.StackEmpty())
{
cout<<s1.StackTop()<<" ";
s1.StackPop();
}
cout<<endl;
}
这样我们就很轻松的利用顺序表和链表适配出了栈
用适配器适配出队列
template<class T,class Container>
class Queue
{
public:
void PushBack(const T& q){_con.PushBack(q);}//入队
void PopFront(){_con.PopFront();}//出队
T& Front(){return _con.Front();}//取队头元素
int Size(){return _con.Size();}//求队列大小
bool Empty(){return _con.Empty();}//判断队列是否为空
protected:
Container _con;
};
测试
void QueueTest()
{
Queue<int,Vector<int>> q;
q.PushBack(1);
q.PushBack(2);
q.PushBack(3);
q.PushBack(4);
q.PushBack(5);
while (!q.Empty())
{
cout<<q.Front()<<" ";
q.PopFront();
}
cout<<endl;
Queue<string,List<string>> q1;
q1.PushBack("change");
q1.PushBack("my");
q1.PushBack("world");
q1.PushBack("come");
q1.PushBack("on !");
while (!q1.Empty())
{
cout<<q1.Front()<<" ";
q1.PopFront();
}
cout<<endl;
}
这样我们就很轻松的利用顺序表和链表适配出了队列
模板的模板参数
上面看起来已经解决了问题,但是如果我不小心这样写了这样的代码:
void QueueTest()
{
Queue<int,Vector<char>> q; //两个类型不一样
Queue<string,List<int>> q1; //两个类型不一样
}
这样的话是不是就会很坑,妥妥的错。为了防止你写出这样的代码,有一种模板参数的方式就杜绝了这种不必要的麻烦。
template <class T,template<class> class Container> //模板的模板参数
class Stack
{
public:
void StackPush(const T& s){_con.PushBack(s);} //入栈
void StackPop(){_con.PopBack();}//出栈
T& StackTop(){return _con.Back();}//取得栈顶元素
bool StackEmpty(){return _con.Empty();}//判断栈是否为空
protected:
Container<T> _con; //模板的模板参数
};
如果这样写就很好解决了防止你把类型传的不一样而导致不必要的错误。
模板的非类型参数
非类型类模板参数
举个例子,假如你要实现动态数组,而且在一个函数里面要用到不同类型的数组,那我们就可以这样。直接看代码:
template<class T,size_t N>
class Array
{
protected:
T array[N];
};
非类型函数模板参数
template<class T,size_t N>
T Add(const T& x)
{
return x+N;
}
非类型模板参数的限制
- 它可以是常整数(包括enum枚举类型)或者指向外部链接对象的指针。
- 浮点数和类对象(class-type)不允许作为非类型模板参数
- 非类型模板参数可以是指针,但该指针必须指向外部链接对象