C++中模板的那些事儿

 C++模板的知识实现顺序表

      模板:是泛型编程的基础

      泛型编程:编写与类型无关的逻辑代码

      说白了模板其实就是一个模具,它是在使用传类型时才存在一个推演的过程,简单的一个模板类的推演过程如下:

     

      

 用模板的方式实现顺序表:

       

#pragma once
#include<iostream>
#include<string>
using namespace std;

template<typename T>
class SeqList
{
	template<typename S>
	friend ostream& operator<<(ostream& os,SeqList<S>& d);
public:
	SeqList();
	SeqList(const SeqList& seq);
	SeqList<T> &operator=(SeqList seq);
	T& operator[](const T& index);
	~SeqList();
public:
	void PushBack(const T& t);
	void PopBack();
	void PushFront(const T& t);
	void PopFront();
	int FindNum(const T& x);
	void Insert(int pos,const T& x);
	void Remove(const T& x);
	void RemoveAll(const T& x);
	void Sort();
	void Display();
public:
	void Reserve(size_t len);
	size_t Size()
	{
		return _size;
	}
	T *_data;
private:
	void CheckCapacity(int count);
	void Copy(T *dest,T *src,int sz);
	size_t GetCapacity()
	{
		return _capacity;
	}
private:
	int _size;
	int _capacity;
};

template<class S>
ostream& operator<<(ostream& os,SeqList<S>& d)
{
	for(int i=0;i<d._size;i++)
	{
		os<<d._data[i]<<" ";
	}
	return os;
}

template<typename T>
SeqList<T>::SeqList()
	:_size(0)
	,_capacity(3)
	,_data(0)
{
	_data=new T[_capacity];
}

template<typename T>
SeqList<T>::SeqList(const SeqList& seq)
{
	T *tmp=new T[seq._capacity];
	for(int i=0;i<seq._size;i++)
	{
		tmp[i]=seq._data[i];
	}
	_data=tmp;
	_size=seq._size;
	_capacity=seq._capacity;
}

template<typename T>
SeqList<T> &SeqList<T>::operator=(SeqList seq)
{
	std::swap(seq._data,_data);
	std::swap(seq._size,_size);
	std::swap(seq._capacity,_capacity);
	return *this;
}

template<typename T>
T& SeqList<T>::operator[](const T& index)
{
	return _data[index];
}

template<typename T>
SeqList<T>::~SeqList()
{
	if(_data != NULL)
	{
		delete[]_data;
		_data=0;
		_size=0;
		_capacity=0;
	}
}

template<typename T>
void SeqList<T>::Display()
{
	for(int i=0;i<_size;i++)
	{
		cout<<_data[i]<<" ";
	}
	cout<<endl;
}

template<typename T>
void SeqList<T>::Reserve(size_t len)
{
	if(GetCapacity() <= len)
	{
		CheckCapacity(len);
	}
	else
	{
		return ;
	}
}

template<typename T>
void SeqList<T>::Copy(T *dest,T *src,int sz)
{
	if(TypeTraits<T>::_IsPodType().Get())
	{
		for(int i=0;i<sz;i++)
		{
			dest[i]=src[i];
		}
	}
	else
	{
		memcpy(dest,src,sz*sizeof(T));
	}
}

template<typename T>
void SeqList<T>::CheckCapacity(int count)
{
	//cout<<typeid(T).name()<<endl;
	if(_size == _capacity)
	{
		int NewCapacity=(2*_capacity)>(_capacity+count)?(2*_capacity):(_capacity+count);
		T *tmp=new T[NewCapacity];
		Copy(tmp,_data,_size);
		delete[]_data;
		_data=tmp;
		_capacity=NewCapacity;
	}
}

template<typename T>
void SeqList<T>::PushBack(const T& t)
{
	CheckCapacity(1);
	_data[_size]=t;
	_size++;
}

template<typename T>
void SeqList<T>::PopBack()
{
	if(_data != 0)
	{
		_size--;
	}
}

template<typename T>
void SeqList<T>::PushFront(const T& t)
{
	CheckCapacity(1);
	for(int i=_size-1;i>=0;i--)
	{
		_data[i+1]=_data[i];
	}
	_data[0]=t;
	_size++;
}

template<typename T>
void SeqList<T>::PopFront()
{
	for(int i=0;i<_size;i++)
	{
		_data[i]=_data[i+1];
	}
	_size--;
}

template<typename T>
int SeqList<T>::FindNum(const T& x)
{
	for(int i=0;i<_size;i++)
	{
		if(_data[i] == x)
			return i;
	}
	return -1;
}

template<typename T>
void SeqList<T>::Insert(int pos,const T& x)   //在指定位置的前面插入元素
{
	CheckCapacity(1);
	for(int i=_size-1;i>=pos;i--)
	{
		_data[i+1]=_data[i];
	}
	_data[pos]=x;
	_size++;
}

template<typename T>
void SeqList<T>::Remove(const T& x)    //删除指定元素
{
	int ret=FindNum(x);
	if(ret != -1)
	{
		for(int i=ret;i<_size-1;i++)
		{
			_data[i]=_data[i+1];
		}
		_size--;
	}
	else
	{
		return ;
	}
}

template<typename T>
void SeqList<T>::RemoveAll(const T& x)   //删除所有指定元素
{
	while(_size != 0)
	{
		int ret=FindNum(x);
		if(ret != -1)
		{
			for(int i=ret;i<_size-1;i++)
			{
				_data[i]=_data[i+1];
			}
			_size--;
		}
		else
		{
			break;
		}
	}
}

template<typename T>
void SeqList<T>::Sort()
{
	int flag=1;
	int m=0;
	int k=0;
	for(int i=0;i<_size-1;i++)
	{
		for(int j=0;j<=k;j++)
		{
			if(_data[i] > _data[i+1])
			{
				T tmp=_data[i];
				_data[i]=_data[i+1];
				_data[i+1]=tmp;
				flag=0;
				m=j;     //m用来记录上一次交换完成的位置
			}
			k=m;
		}
		if(flag == 1)
			break;
	}
}

 

 模板的模板参数-容器适配器
   我们知道栈是先进后出的一种数据结构,而如果我们要模拟实现栈的这种数据结构我们发现顺序表是最好的选择,因为效率高,栈的插入和删除正好对应的是顺序表的尾插和尾删

   

//模板参数
//template<class T,class Container=SeqList>
//模板的模板参数
template<class T,template<class>class Container=SeqList>
class Stack
{
public:
	void Push(const T& d)
	{
		_con.PushBack(d);
	}
	void Pop()
	{
		_con.PopBack();
	}
	bool Empty()
	{
		return _con.Size() == 0;
	}
	T& Top()
	{
		int sz=_con.Size();
		return _con._data[--sz];
	}
	void Display()
	{
		while(!Empty())
		{
			cout<<Top()<<" ";
			Pop();
		}
		cout<<endl;
	}
private:
	Container<T> _con;
};


测试代码:

  

void test5()
{
	Stack<int> s;
	s.Push(1);
	s.Push(2);
	s.Push(3);
	s.Push(4);
	s.Push(5);
	s.Display();
}


 

 类型萃取的实例应用一:SeqList

        类型萃取其实就是区分内置类型和自定义类型

      

#define _CRT_SECURE_NO_WARNINGS 1
struct _TrueType
{
	int Get()
	{
		return 1;
	}
};

struct _FalseType
{
	int Get()
	{
		return -1;
	}
};

template<typename T>  //自定义类型
struct TypeTraits
{
	typedef _FalseType _IsPodType;
};

template<>    //内置类型
struct TypeTraits<int>
{
	typedef _TrueType _IsPodType;
};

template<>
struct TypeTraits<double>
{
	typedef _TrueType _IsPodType;
};

template<>
struct TypeTraits<char>
{
	typedef _TrueType _IsPodType;
};

template<typename T>
void Copy(T *dest,T *src,int sz,_TrueType)
{
	memcpy(dest,src,sz*sizeof(T));
}

template<typename T>
void Copy(T *dest,T *src,int sz,_FalseType)
{
	for(int i=0;i<sz;i++)
	{
		dest[i]=src[i];
	}
}

template<typename T>
void Copy(T *dest,T *src,int sz)
{
	if(TypeTraits<T>::_IsPodType().Get())
	{
		for(int i=0;i<sz;i++)
		{
			dest[i]=src[i];
		}
	}
	else
	{
		memcpy(dest,src,sz*sizeof(T));
	}
}


测试代码:

  

void testTypeTraits()
{
	string s1[10]={"abcd","bcde","defg","bbbxxxxxxxxxxxxxxxxxxxxx"};
	string s2[10]={"12","23","34","45"};
	Copy(s1,s2,10,TypeTraits <string>::_IsPodType());
	Copy(s1,s2,10);
	int a1[10]={1,2,3};
	int a2[10]={0};
	Copy(a1,a2,10,TypeTraits <int>::_IsPodType());
	Copy(a1,a2,10);
}


C++模板的知识实现链表:

     C++实现链表:

 

#pragma once
#include<cstring>
#include<iostream>
using namespace std;

template<typename T>
struct Node
{
	template<typename T>
	friend ostream& operator<<(ostream& os,Node<T>& n)
	{
		os<<n._data;
		return os;
	}
public:
	Node(const T& d)
		:_next(NULL)
		,_front(NULL)
		,_data(d)
	{}
	T _data;
	Node<T>* _next;
	Node<T>* _front;
};

template<typename T>
class LinkList
{
	template<typename T>
	friend ostream& operator<<(ostream& os,LinkList<T>& list);
public:
	LinkList()
		:_head(0)
		,_tail(0)
	{}
	LinkList(const LinkList<T>& list);
	LinkList<T>& operator=(LinkList<T> list);
	~LinkList();
public:
	void PushBack(const T& d);
	void PopBack();
	void PushFront(const T& d);
	void PopFront();
	Node<T> *FindNum(const T& x);
	void Insert(Node<T> *pos,const T& x);
	void Insert(int,Node<T> *pos,const T& x);
	void Remove(const T& x);
	void RemoveAll(const T& x);
	void Sort();
	void Display()
	{
		Node<T>* cur=_head;
		while(cur)
		{
			cout<<cur->_data<<" ";
			cur=cur->_next;
		}
		cout<<endl;
	}
public:
	Node<T>* GetFront()
	{
		return _head;
	}
	Node<T>* GetTail()
	{
		return _tail;
	}
	size_t Size();
private:
	Node<T> *_head;
	Node<T> *_tail;
};

template<typename T>
ostream& operator<<(ostream &os,LinkList<T> &list)
{
	Node<T> *cur=list._head;
	while(cur)
	{
		os<<(*cur)<<" ";
		cur=cur->_next;
	}
	return os;
}

template<typename T>
LinkList<T>::LinkList(const LinkList<T>& list)
	:_head(0)
	,_tail(0)
{
	Node<T>* cur=list._head;
	while(cur)
	{
		PushBack(cur->_data);
		cur=cur->_next;
	}
}

template<typename T>
LinkList<T>& LinkList<T>::operator=(LinkList<T> list)
{
	std::swap(list._head,_head);
	std::swap(list._tail,_tail);
	return *this;
}

template<typename T>
LinkList<T>::~LinkList()
{
	Node<T>* cur=_head;
	while(cur != 0)
	{
		Node<T>* del=cur;
		cur=cur->_next;
		delete del;
		del=NULL;
	}
	_head=NULL;
	_tail=NULL;
}

template<typename T>
void LinkList<T>::PushBack(const T& d)
{
	Node<T> *NewNode=new Node<T>(d);
	if(_head == NULL)
	{
		_head=NewNode;
		_tail=NewNode;
	}
	else
	{
		_tail->_next=NewNode;
		NewNode->_front=_tail;
		_tail=NewNode;
	}
}

template<typename T>
void LinkList<T>::PopBack()
{
	if(!_head)    //空链表
	{
		return ;
	}
	else if(!_head->_next)     //只有一个节点
	{
		delete _tail;
		_head=NULL;
		_tail=NULL;
	}
	else      //至少存在两个节点
	{
		_tail=_tail->_front;
		delete _tail->_next;
		_tail->_next=0;
	}
}

template<typename T>
void LinkList<T>::PushFront(const T& d)
{
	Node<T> *NewNode=new Node<T>(d);
	if(_head)
	{
		Node<T> *tmp=_head;
		NewNode->_next=tmp;
		tmp->_front=NewNode;
	}
	else    //空链表
	{
		_tail=NewNode;
	}
	_head=NewNode;    //更新头
}

template<typename T>
void LinkList<T>::PopFront()
{
	if(!_head)    //空链表
	{
		return ;
	}
	else if(!_head->_next)  //只有一个结点
	{
		delete _head;
		_head=NULL;
		_tail=NULL;
	}
	else         //至少存在两个结点
	{
		_head=_head->_next;
		delete _head->_front;
		_head->_front=NULL;
	}
}

template<typename T>
Node<T> *LinkList<T>::FindNum(const T& x)
{
	Node<T> *cur=_head;
	while(cur)
	{
		if(cur->_data == x)
			return cur;
		cur=cur->_next;
	}
	return NULL;
}

template<typename T>
void LinkList<T>::Insert(Node<T> *pos,const T& x)    //在指定位置后插
{
	Node<T> *NewNode=new Node<T>(x);
	if(pos->_next)
	{
		NewNode->_front=pos;
		NewNode->_next=pos->_next;
		pos->_next->_front=NewNode;
		pos->_next=NewNode;
	}
	else    //在最后一个结点后插,类似PushBack
	{
		pos->_next=NewNode;
		NewNode->_front=pos;
		_tail=NewNode;    //更新尾
	}
}

template<typename T>
void LinkList<T>::Insert(int,Node<T> *pos,const T& x)   //在指定位置前插
{
	Node<T> *NewNode=new Node<T>(x);
	if(pos->_front)
	{
		NewNode->_next=pos;
		pos->_front->_next=NewNode;
		NewNode->_front=pos->_front;
		pos->_front=NewNode;
	}
	else   //在第一个结点的前插,类似PushFront
	{
		NewNode->_next=pos;
		pos->_front=NewNode;
		_head=NewNode;    //更新头
	}
}

template<typename T>
void LinkList<T>::Remove(const T& x)
{
	Node<T> *pos=this->FindNum(x);
	if(pos != 0)
	{
		if((!(pos->_front)) && pos->_next)    //删除第一个结点
		{
				Node<T> *tmp=pos->_next;
				tmp->_front=NULL;
				_head=tmp;
		}
		else if(pos->_front && (!(pos->_next)))   //删除最后一个结点
		{
			Node<T> *tmp=pos->_front;
			tmp->_next=NULL;
			_tail=tmp;
		}
		else             //删除中间节点
		{
			Node<T> *front=pos->_front;
			Node<T> *next=pos->_next;
			next->_front=front;
			front->_next=next;
		}
		delete pos;
		pos=0;
	}
}

template<typename T>
void LinkList<T>::RemoveAll(const T& x)
{
	Node<T> *cur=_head;
	Node<T> *ret=this->FindNum(x);
	if(ret != _head)    //可删除第一个结点不是要删除的元素
	{
		while(cur)
		{
			Remove(x);
			cur=cur->_next;
		}
	}
}

template<typename T>
void LinkList<T>::Sort()
{
	int flag=1;
	Node<T> *cur=_head;
	Node<T> *tail=NULL;
	while(cur != tail)
	{
		while(cur->_next != tail)
		{
			if(cur->_data > cur->_next->_data)
			{
				T tmp=cur->_data;
				cur->_data=cur->_next->_data;
				cur->_next->_data=tmp;
				flag=0;
			}
			cur=cur->_next;
		}
		if(flag == 1)
			break;
		tail=cur;
		cur=_head;
	}
}

template<typename T>
size_t LinkList<T>::Size()
{
	Node<T>* cur=_head;
	size_t count=0;
	while(cur)
	{
		count++;
		cur=cur->_next;
	}
	return count;
}


  模板参数-容器适配器

   借用链表的某些函数实现队列这种数据结构,队列:先进先出,之所以使用链表的方式而不使用顺序表,因为顺序表在插入一个元素时需要大量移动元素而链表则不需要,我们发现针对队列的这种数据结构,它的插入和删除则正好对应链表的尾插和头删

  

//模板参数
template<class T,class Container=LinkList>
class Queue
{
public:
	void Push(const T& d)
	{
		_con.PushBack(d);
	}
	void Pop()
	{
		_con.PopFront();
	}
	Node<T>& Front()
	{
		return *_con.GetFront();
	}
	Node<T>& Back()
	{
		return *_con.GetTail();
	}
	bool Empty()
	{
		return _con.GetFront() == 0;
	}
	size_t Size()
	{
		return _con.Size();
	}
	void Display()
	{
		while(!Empty())
		{
			cout<<Front()._data<<" ";
			Pop();
		}
		cout<<endl;
	}
private:
	Container _con;
};


 测试代码:

 

void testQueue()
{
	Queue<int,LinkList<int>> q1;
	q1.Push(1);
	q1.Push(2);
	q1.Push(3);
	q1.Push(4);
	q1.Push(5);
	cout<<q1.Size()<<endl;   //5
	q1.Display();
}

 

      如果对模板还有兴趣请观赏《C++ templates》这本书,Thanks

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值