C++实验3 模板

一.模板函数

定义:函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能

为了交换两个整型变量的值,需要写下面的 Swap 函数:

void Swap(int & x, int & y)
{
    int tmp = x;
    x = y;
    y = tmp;
}

为了交换两个 double 型变量的值,还需要编写下面的 Swap 函数:

void Swap (double & xr double & y)
{
    double tmp = x;
    x = y;
    y = tmp;
}

如果还要交换两个 char 型变量的值需要再编写 Swap 函数。而这些 Swap 函数除了处理的数据类型不同外,形式上都是一样的。能否只写一遍 Swap 函数,就能用来交换各种类型的变量的值呢?继承和多态显然无法解决这个问题。因此,“模板”的概念就应运而生了。

1.1 一般模板函数

写法如下:

template 
返回值类型  模板名(形参表)
{
    函数体
}

class也可以换成typename,如下:

template 

模板函数看上去就像函数,Swap函数如下:

template 
void Swap(T & x, T & y)
{
    T tmp = x;
    x = y;
    y = tmp;
}

T 是类型参数,代表类型。编译器由模板自动生成函数时,会用具体的类型名对模板中所有的类型参数进行替换,其他部分则原封不动地保留。同一个类型参数只能替换为同一种类型。编译器在编译到调用函数模板的语句时,会根据实参的类型判断该如何替换模板中的类型参数。

1.2 特化模板函数

使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数(就是写出一个模板函数专门给该类型使用)

一个判断相等的函数:

template
bool Isequal(T& p1, T& p2){
	return p1 == p2;
}
 

但是该模板函数在对于字符串进行比较时就不能使用了,对于字符串我们不能直接比较,因此直接特化出一个专门供字符串使用的模板参数

template<> // 此处不添加类型模板,直接使用空即可
bool Isequal(char*& p1, char*& p2){
	return strcmp(p1, p2) == 0;
}

【注意】

  • 使用模板特化时,必须要先有基础的模板函数(就是上面第一个模板函数)

  • 使用特换模板函数时格式有要求:

    1.template 后直接跟<> 里面不用写类型
    2.函数名<特化类型>(特化类型 参数1, 特化类型 参数2 , …) 在函数名后跟<>其中写要特化的类型

  • 特化的函数的函数名,参数列表要和原基础的模板函数想相同,避免不必要的错误

二.模板类Queue或Stack

1.1 模板类Queue

队列(queue)是先进先出的数据结构,存储方式可以是数组也可以是链表。如果用数组存储,一般采用循环队列的方式。

所以需记住几个关键点:

队头指针进1:front = (front+1)%maxsize

队尾指针进1:rear = (rear+1)%maxsize

判断队空:front = rear

判断队满:front = (rear+1)%maxsize,这里,队满的时候队尾和队头之间空有一个元素,以此来避免和front=rear混淆

定义头文件
 

/*队列用数组存储的一般用循环队列
  front = (front+1)%maxsize
  rear = (rear+1)%maxsize
  队头指向存储的第一个元素,而队尾指向的是存储的最后一个元素的下一个位置
  所以,在队列满的时候,队头和队尾之间是空有一个元素的,否则当front==rear时,
  会混淆满队和空队
  空队:front == rear
  满队:(rear+1)%maxsize ==front
*/
 
#include 
#include
using namespace std;
 
template
class SeqQueue{
public:
	SeqQueue(int sz=50);
	~SeqQueue();
	bool EnQueue(const T& x);
	bool DeQueue();
	T getFront(); //获取队头元素
	bool makeEmpty(){front = rear =0; return true;}
	bool isEmpty()const{return (front==rear)?true:false;}
	bool isFull()const{return ((rear+1)%maxsize==front)?true:false;}
	int getsize()const{return (rear-front+maxsize)%maxsize;}  //获取队列元素个数
private:
	int front,rear;
	T* element;
	int maxsize;
};
 

成员函数的实现

#include "queue.h"
 
template
SeqQueue::SeqQueue(int sz):maxsize(sz):front(0):rear(0){
	element = new T[maxsize];
	assert(element!=NULL);
}
 
template
bool SeqQueue::EnQueue(const T& x){
	if(isFull()==true)return false;
	element[rear]=x;
	rear = (rear+1)%maxsize;
	return true;
}
 
template
bool SeqQueue::DeQueue(){
	if(isEmpty()==true)return false;
	T x = element[front];
	front = (front+1)%maxsize;
	delete x;
	return true;
}
 
template
T SeqQueue::getFront(){
	if(isEmpty()==true)return -1;
	return element[front];
}
 

1.2 模板类Stack

头文件

#include
#include
using namespace std;
 
const int stackIncreament=20;
template
class SeqStack{
public:
	SeqStack(int sz = 50);
	~SeqStack();
	bool push(const T& x);
	bool pop(const T& x);
	bool isFull()const{return (top == maxsize-1)?true:false;}
	bool isEmpty()const{return (top ==-1)?true:false;}
	int getsize(){return top+1;}
	T gettop();
	void makeEmpty(){top = -1;}
private:
	T * element;
	int maxsize;
	int top;
	void overflowProcess();
};

成员函数实现

#include "queue.h"
 
template
SeqQueue::SeqQueue(int sz):maxsize(sz):front(0):rear(0){
	element = new T[maxsize];
	assert(element!=NULL);
}
 
template
bool SeqQueue::EnQueue(const T& x){
	if(isFull()==true)return false;
	element[rear]=x;
	rear = (rear+1)%maxsize;
	return true;
}
 
template
bool SeqQueue::DeQueue(){
	if(isEmpty()==true)return false;
	T x = element[front];
	front = (front+1)%maxsize;
	delete x;
	return true;
}
 
template
T SeqQueue::getFront(){
	if(isEmpty()==true)return -1;
	return element[front];
}
 

1.3 模板特化

1.3.1.1 函数模板

template 
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

template 
T add(T a, T b)
{
	return a + b;
}

template 
T2 Add(const T1& a, const T2& b)
{
	return a + b;
}

int Add(const int& a, const int& b)
{
	return a + b;
}

1.3.1.2 函数模板特化

函数模板
template 
T Add(T& a, T& b)
{
	return a + b;
}

函数模板的特化
template <>
char* Add(char*& a, char*& b)
{
	strcat(a, b);
	return a;
}

普通函数
char* Add(char*& a, char*& b)
{
	strcat(a, b);
	return a;
}

 1.3.2 类模板及特化

  1.3.2.1 类模板

  

template 
class Date
{
public:
	Date(T1 year, T2 month, T3 day)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	void Display();
	/*{
		cout << _year << "-" << _month << "-" << _day << endl;
	}*/
private:
	T1 _year;
	T2 _month;
	T3 _day;
};

1.3.2.2 类模板特化

特化之前需要存在基础类模板
template 
class A
{
public:
	A()
	{
		cout << "A(T1, T2)" << endl;
	}
private:
	T1 _t1;
	T2 _t2;
};

全特化--> 所有的参数都为具体类型
template <>
class A
{
public:
	A()
	{
		cout << "A(int, char)" << endl;
	}
private:
	int _t1;
	char _t2;
};



偏特化: a. 部分特化
template 
class A
{
public:
	A()
	{
		cout << "A(T1, double)" << endl;
	}
private:
	T1 _t1;
	double _t2;
};

template 
class A
{
public:
	A()
	{
		cout << "A(T1, char)" << endl;
	}
private:
	T1 _t1;
	double _t2;
};

b. 对模板参数做进一步的限制
template 
class A
{
public:
	A()
	{
		cout << "A(T1&, T2&>" << endl;
	}
};

三.类模板模拟智能指针auto_ptr

#include 
using namespace std;
 
template 
class autoptr{
	T* p;
public:	
	autoptr(T* p=0):p(p){}
	~autoptr(){delete p;}
	autoptr(autoptr& a):p(0){operator=(a);}
	//autoptr(autoptr& a){operator=(a);}//错误的拷贝构造函数,p没有初始化,将是野指针,会delete出错
	autoptr& operator=(autoptr& a){
		if(this==&a) return *this;
		/*如果之前管理的内存不为空,释放之前管理的内存*/
		if(p!=NULL) {
			//cout << "free previous memory\n";
			delete p;
		}
		p = a.p;
		a.p = NULL;
		return *this;
	}
	/* *和->重载 */
	T& operator*()const{return *p;}
	T* operator->()const{return p;}
};
class A{
	int data;
public:
	A(int d):data(d){cout< p(new A(10));
	p->show();
	autoptr q(p);
	//p->show();出错,p已经没有动态内存的所有权了
	q->show();
	autoptr r(new A(20));
	(*r).show();
	r = q;
	r->show();
	(*r).show();
	autoptr x;
	x=r;
	(*x).show();
}
 

运行结果

C++实验3 模板_第1张图片

 

你可能感兴趣的:(c++,开发语言,后端)