一.模板函数
定义:函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能
为了交换两个整型变量的值,需要写下面的 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();
}
运行结果
?
|