实验要求:
熟悉C
1. 函数模板(Function Templates)
重载设计中,最理想的是对不同的参数类型做不同的事情。
比如swap函数,对于任何一个类型T的两个对象a、b,总能调用合适的swap(a,b)——函数模板实现
函数模板的定义:
关键字template告诉编译器,将要定义一个模板。
<>内的相当于函数的参数列表(模板形参 或 类型参数),每个模板形参都必须加上前缀typename
或class
泛型标识符,例如Typename或T,称为类型参数(Type parameter),这意味这它们类似于变量,但是赋给它们的不能是数字,只能是类型。
例如:
template<class T>
int compare(const T&a,const T&b){
if(a<b) return -1;
else if(a>b) return 1;
else return 0;
}
模板形参T(T为泛型名),数据形参a、b,函数返回类型int 。
函数模板不是函数,它是以具体的类型参数为实参来生成函数的模板。
函数模板定义被编译时,不会产生任何可执行代码。
类模板(Class Template)
如果让模板来工作,即省心又不降低效率,而且编译器依然可以对代码进行类型检查,还能保持代码的优雅和简洁。
类模板是一种模板,它通过在类定义上铺设类型参数的形式,表示具有相似操作的系列类(类族)。
template< class T> class Queue
;中的Queue,即类模板名(class template name),简称模板名(template name)
类模板不是类,而模板类是类。
template<class T>
class Queue;
template<class T>
class QueueItem{
//public:
private:
T item;
QueueItem *next;
friend Queue<T>;
QueueItem(const T &t):item(t),next(){}
// friend ostream & operator<<(ostream &os,Queue<T> &q);
friend ostream & operator<<(ostream &os,const Queue<T> &q);
};
template<class T>
class Queue{
private:
QueueItem<T> *head;
QueueItem<T> *tail;
//friend ostream & operator<<(ostream &os,const Queue<T> &q);
friend ostream & operator<<(ostream &os,const Queue<T> &q){
QueueItem<T> *p=q.head;
// Queue<T> *p=q.head;
os<<"< ";
while(p){
os<<p->item<<" ";
p=p->next;
}
os<<">"<<endl;
return os;
}
void Destroy();
public:
Queue():head(0),tail(0){}
Queue(const Queue<T> &q){
copyItems(q);
}
void push(const T &t);
void pop();
bool isEmpty(){
return head==0;
}
T & front(){
if(!isEmpty()){
return head->item;
}
}
~Queue(){
Destroy();
}
void copyItems(const Queue<T> &q);
template<class It>
void copyItems(It beg,It end);
template<class It>
Queue(It beg,It end):head(0),tail(0){
copyItems(beg,end);
}
template<class It>
void assign(It beg,It end);
Queue & operator=(const Queue&);
Queue & operator()(const Queue&);
};
类模板实例化的过程,是根据具体的模板实参,替换成模板形参而产生除对应的模板类的过程。
例如:
Queue<int> l1;
模板特化
可以用模板实参来定做模板类。
类模板的模板实参通过实例化,构成模板的实例,它是定义好的模板类。
如果不想使用预定义的类模板来生成模板类,则是以该模板类名自己专门重写一个模板类,则得到模板特化(template specialization),得到模板特化的过程,称为模板定做(template specializing)
模板定做时, template<> class 类模板名
以下为局部定做(partial specialization)
申明(放在.h文件中) :
template<>
int compare<const char*>(const char * const &v1, const char * const &v2);
template<>
void Queue<const char*>::push(const char* const &t);
template<>
void Queue<const char*>::pop();
实现(只能放在.cpp文件中):
template<>
void Queue<const char*>::push(const char* const &t){
char *p=new char [strlen(t)+1];
strncpy(p,t,strlen(t)+1);
QueueItem<const char*>*qi=new QueueItem<const char*>(p);
if(isEmpty()){
head=tail=qi;
}
else{
tail->next=qi;
tail=qi;
}
}
template<>
void Queue<const char*>::pop(){
QueueItem<const char*>*qi=head;
head=head->next;
delete[] qi->item;
delete qi;
}
template<>
int compare<const char*>(const char* const &a,const char* const &b){
return strcmp(a,b);
}
实验部分
(熟悉C++的函数模板的使用并实现自己定义的队列)
sy3.h
#ifndef sy3
#define sy3
#include <iostream>
#include <string.h>
using namespace std;
template<class T>
class Queue;
template<class T>
class QueueItem{
//public:
private:
T item;
QueueItem *next;
// friend Queue<T>;
friend Queue<T>;
QueueItem(const T &t):item(t),next(){}
// friend ostream & operator<<(ostream &os,Queue<T> &q);
friend ostream & operator<<(ostream &os,const Queue<T> &q);
};
template<class T>
class Queue{
private:
QueueItem<T> *head;
QueueItem<T> *tail;
//friend ostream & operator<<(ostream &os,const Queue<T> &q);
friend ostream & operator<<(ostream &os,const Queue<T> &q){
QueueItem<T> *p=q.head;
// Queue<T> *p=q.head;
os<<"< ";
while(p){
os<<p->item<<" ";
p=p->next;
}
os<<">"<<endl;
return os;
}
void Destroy();
public:
Queue():head(0),tail(0){}
Queue(const Queue<T> &q){
copyItems(q);
}
void push(const T &t);
void pop();
bool isEmpty(){
return head==0;
}
T & front(){
if(!isEmpty()){
return head->item;
}
}
~Queue(){
Destroy();
}
void copyItems(const Queue<T> &q);
template<class It>
void copyItems(It beg,It end);
template<class It>
Queue(It beg,It end):head(0),tail(0){
copyItems(beg,end);
}
template<class It>
void assign(It beg,It end);
Queue & operator=(const Queue&);
Queue & operator()(const Queue&);
};
template<class T>
void Queue<T>::push(const T &t){
QueueItem<T> *pItem = new QueueItem<T>(t);
if(isEmpty()){
head=tail=pItem;
}
else{
tail->next=pItem;
tail=pItem;
}
}
template<class T>
void Queue<T>::pop(){
if(isEmpty())
return;
QueueItem<T> *p=head;
head=head->next;
delete p;
}
template<>
void Queue<const char*>::push(const char* const &t);
template<>
void Queue<const char*>::pop();
template<class T>
void Queue<T>::Destroy(){
while(!isEmpty()){
pop();
}
}
template<class T>
void Queue<T>::copyItems(const Queue<T> &q){
QueueItem<T> *p=q.head;
while(p){
push(p->item);
p=p->next;
}
}
template<class T>
template<class It>
void Queue<T>::copyItems(It beg,It end){
while(beg!=end){
push(beg);
beg++;
}
}
template<class T>
Queue<T> &Queue<T>::operator=(const Queue & q){
Destroy();
copyItems(q);
}
template<class T>
Queue<T> &Queue<T>::operator()(const Queue & q){
Destroy();
copyItems(q);
}
template<class T>
template<class It>
void Queue<T>::assign(It beg,It end){
Destroy();
copyItems(beg,end);
}
template<class T>
int compare(const T&a,const T&b){
if(a<b) return -1;
else if(a>b) return 1;
else return 0;
}
template<>
int compare<const char*>(const char* const &a,const char* const &b);
#endif
sy3.cpp
#include "sy3.h"
#include<string>
#include<string.h>
using namespace std;
//类部分模板特化
template<>
void Queue<const char*>::push(const char* const &t){
char *p=new char [strlen(t)+1];
strncpy(p,t,strlen(t)+1);
QueueItem<const char*>*qi=new QueueItem<const char*>(p);
if(isEmpty()){
head=tail=qi;
}
else{
tail->next=qi;
tail=qi;
}
}
template<>
void Queue<const char*>::pop(){
QueueItem<const char*>*qi=head;
head=head->next;
delete[] qi->item;
delete qi;
}
template<>
int compare<const char*>(const char* const &a,const char* const &b){
return strcmp(a,b);
}
main.cpp
#include <iostream>
#include "sy3.h"
using namespace std;
//class Queue 的使用
int main() {
Queue<int> l1;
int a=1,b=2,c=3;
l1.push(a);
l1.push(b);
l1.push(c);
cout<<"l1"<<l1;
l1.pop();
cout<<"l1"<<l1;
Queue<double> l2;
double d=1.1,e=2.2,f=3.3;
l2.push(d);
l2.push(e);
l2.push(f);
cout<<"l2"<<l2;
double front=l2.front();
cout<<l2.front()<<endl;
int x[5]={1,2,3,4,5};
int y[5]={11,12,13,14,15};
Queue<int> l3(1,4);
cout<<"l3"<<l3;
Queue<double> l4;
l4.copyItems(l2);
cout<<"l4"<<l4;
Queue<int> l5;
l5.copyItems(11,15);
cout<<"l5"<<l5;
Queue<double> l6;
l6(l4);
cout<<"l6"<<l6;
Queue<int> l7;
//l7=l4;
l7.copyItems(1,3);
cout<<"l7"<<l7;
cout<<"compare(2,12)"<<compare(2,12)<<endl;
cout<<"------------------------------------------"<<endl;
cout<<"compare('ad','ab')"<<compare('ad','ab')<<endl;
Queue<const char*>q1;
q1.push("q1");
q1.push("is");
q1.push("there");
cout<<"q1"<<q1;
q1.pop();
cout<<"q1"<<q1;
/**/
Queue<const char*>q2;
//q2.copyItems(q1);
q2(q1);
cout<<"q2"<<q2;
Queue<const char*>q3;
q3=q1;
cout<<"q3"<<q2;
return 0;
}