IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++实验3 模板 -> 正文阅读

[C++知识库]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 类型参数1, class类型参数2, ...>
返回值类型  模板名(形参表)
{
    函数体
}

class也可以换成typename,如下:

template <typename 类型参数1, typename 类型参数2, ...>

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

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

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

1.2 特化模板函数

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

一个判断相等的函数:

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

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

template<> // 此处不添加类型模板,直接使用空即可
bool Isequal<char*>(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 <assert.h>
#include<iostream>
using namespace std;
 
template<class T>
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<class T>
SeqQueue<T>::SeqQueue(int sz):maxsize(sz):front(0):rear(0){
	element = new T[maxsize];
	assert(element!=NULL);
}
 
template<class T>
bool SeqQueue<T>::EnQueue(const T& x){
	if(isFull()==true)return false;
	element[rear]=x;
	rear = (rear+1)%maxsize;
	return true;
}
 
template<class T>
bool SeqQueue<T>::DeQueue(){
	if(isEmpty()==true)return false;
	T x = element[front];
	front = (front+1)%maxsize;
	delete x;
	return true;
}
 
template<class T>
T SeqQueue<T>::getFront(){
	if(isEmpty()==true)return -1;
	return element[front];
}
 

1.2 模板类Stack

头文件

#include<assert.h>
#include<iostream>
using namespace std;
 
const int stackIncreament=20;
template<class T>
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<class T>
SeqQueue<T>::SeqQueue(int sz):maxsize(sz):front(0):rear(0){
	element = new T[maxsize];
	assert(element!=NULL);
}
 
template<class T>
bool SeqQueue<T>::EnQueue(const T& x){
	if(isFull()==true)return false;
	element[rear]=x;
	rear = (rear+1)%maxsize;
	return true;
}
 
template<class T>
bool SeqQueue<T>::DeQueue(){
	if(isEmpty()==true)return false;
	T x = element[front];
	front = (front+1)%maxsize;
	delete x;
	return true;
}
 
template<class T>
T SeqQueue<T>::getFront(){
	if(isEmpty()==true)return -1;
	return element[front];
}
 

1.3 模板特化

1.3.1.1 函数模板

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

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

template <class T1,class T2>
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 <class T>
T Add(T& a, T& b)
{
	return a + b;
}

函数模板的特化
template <>
char* Add<char*>(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 T1, class T2, class T3>
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 T1, class T2>
class A
{
public:
	A()
	{
		cout << "A(T1, T2)" << endl;
	}
private:
	T1 _t1;
	T2 _t2;
};

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



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

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

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

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

#include <iostream>
using namespace std;
 
template <typename T>
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<<this<<"A("<<d<<")"<<endl;}
	~A(){cout<<this<<"~A()"<<data<<endl;}
	void show()const{cout<<this<<":"<<data<<endl;}
};
int main()
{
	autoptr<A> p(new A(10));
	p->show();
	autoptr<A> q(p);
	//p->show();出错,p已经没有动态内存的所有权了
	q->show();
	autoptr<A> r(new A(20));
	(*r).show();
	r = q;
	r->show();
	(*r).show();
	autoptr<A> x;
	x=r;
	(*x).show();
}
 

运行结果

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-17 12:34:54  更:2021-11-17 12:36:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:05:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码