模板类声明,类模板的实例化
C\C++作为强类型语言,变量和函数参数、返回值是一定要声明类型模板类声明的,对于某些算法来说,除模板类声明了数据类型不同以外,其它代码(逻辑)都是一样模板类声明的。
模板类声明我们希望能够将这些通用性较强的算法做成模板(Template),只需要填入相应的数据类型,就能立刻可用。
C++中的模板分为两种模板类声明:函数模板和类模板,分别适用于面向过程和面向对象的程序设计。
1 函数模板函数模板是一系列相关函数的模型或样板,这些函数的源代码形式相同,只是所针对的数据类型不同。对于函数模板,数据类型本身成了它的参数,因而是一种参数化类型的函数。
函数模板与普通函数相似,也有函数模板原型、函数模板头、函数模板体。
函数模板的原型为:
template <数据类型参数表> 返回值类型 函数名(参数表);例如:template <class T,class U>U func(T a,int b,U c);数据类型参数是一种特殊的参数,其填入的实参并不是一个数据,而是一种数据类型,如int、char。
在数据类型参数的作用域之内,该参数的标识符就用来代表一种数据类型。
两个变量或存储区域的数据交换与数据的类型无关,无论整型、浮点型、字符型都可以进行数据交换。
尽管如此,当两个字符串(字符数组)进行交换时,与两个普通的变量交换又有所不同。(字符数组做为函数参数时,数组名是一个常量指针,不能用作左值。)
对于绝大多数变量,采用函数模板的方式实现交换。
对于字符串(字符数组),采用重载函数的方式实现交换。
实例代码:
运行结果:
交换后为2,3
交换后为b,a
交换后为Shanghai University,Tomato Studio
在C++中,函数模板与重载可以同时使用。只要使该函数模板的名称与重载函数的名称相同即可。
当调用一个函数时,优先调用重载函数。如果没有重载,则查找是否有同名的函数模板,并根据调用时实参的类型依照函数模板生成一个“临时”的重载函数后调用。
实例代码:
运行结果:
8
2.65
Tomato Studio
Tomato
2 类模板类模板就是一系列相关类的模板或样板,这些类的成员组成相同,成员函数的源代码形式相同,所不同的只是针对的类型(数据成员的类型以及成员函数的参数和返回值的类型)。对应类模板,数据类型本身成了参数,因而是一种参数化类型的类,是类的生成器。类模板中声明的类称为模板类。
与普通的类相似,类模板也需要声明和定义。声明一个类模板的 *** 为:
template <数据类型参数表> class 类模板名;例如:template <class T> class Buffer;类模板通常应用于对各种数据类型适用的数据存储类。例如链表类、向量(数组)类、栈类等。
通过使用链表类模板,可以创建出存储整型的链表、存储字符的链表以及存储字符串的链表。
类模板的定义与类的定义相似,但在某些合适的地方将具体的数据类型改为数据类型参数。例如:
对于在类模板定义内定义的成员函数,与一般的成员函数在类定义内的定义方式一致。
对于在类模板定义外定义的成员函数,格式为:
template <数据类型参数表> 返回值类型 模板名<类型参数顺序表>::成员函数名(参数表) { 语句1; 语句2; …… }在使用类模板时,先要填入对应的数据类型参数,使其变成一个完整的类,然后再用这个类来创建一个对象。因此,用类模板创建一个对象的 *** 为:
类模板名<数据类型列表> 对象名(初始化数据);
实例代码:
运行效果:
请输入一个整数:4Node constructor is running...Linklist constructor is running...Node constructor is running...Node constructor is running...After Linklista Insert421请输入一个字符:eNode constructor is running...Linklist constructor is running...Node constructor is running...Node constructor is running...After Linklist b InsertePC附代码1:
#include <iostream>using namespace std;template <class T> void Swap(T &a,T &b);void Swap(char a[],char b[]);int main(){ int a=3,b=2; //int和char变量用函数模板实现交换 char c='a',d='b'; char s1[32]="Tomato Studio"; //字符数组要用重载函数实现交换 char s2[32]="Shanghai University"; Swap(a,b); //调用函数模板 cout <<"交换后为" <<a <<"," <<b <<endl; Swap(c,d); //调用函数模板 cout <<"交换后为" <<c <<"," <<d <<endl; Swap(s1,s2); //调用重载函数 cout <<"交换后为" <<s1 <<"," <<s2 <<endl; system("pause"); return 0;}template <class T> void Swap(T &a,T &b){ T temp=a; //简单交换 a=b; b=temp; return;}void Swap(char a[],char b[]){ int i; char temp[32]; //临时数组 for (i=0;a[i]!='\0';i++) temp[i]=a[i]; //所有a数组元素复制到temp数组 temp[i]='\0'; //填补结尾符 for (i=0;b[i]!='\0';i++) a[i]=b[i]; //所有b数组元素复制到a数组 a[i]='\0'; for (i=0;temp[i]!='\0';i++) b[i]=temp[i]; //所有temp数组元素复制到b数组 b[i]='\0'; return;}附代码2:
#include <iostream>#include <string>using namespace std;template <class T>T *** aller( T a, T b ) /* 函数模板 */{ if ( a <= b ) { return(a); }else { return(b); }}char * *** aller( char *a, char *b ) /* 重载函数 */{ if ( strlen( a ) <= strlen( b ) ) /* strlen函数返回字符串的长度 */ { return(a); }else { return(b); }}int main(){ cout << *** aller( 8, 22 ) << endl; cout << *** aller( 99.88, 2.65 ) << endl; cout << *** aller( "Tomato Studio", "Shanghai University" ) << endl; cout << *** aller( "Tomato", "tomato" ) << endl; system( "pause" ); return(0);}附代码3:
//3个文件
//main.cpp
//linklist.h
//node.h
//main.cpp
#include "linklist.h"
#include <iostream>
using namespace std;
int main()
{
int tempi;
char tempc;
cout <<"请输入一个整数:" <<endl;
cin >>tempi;
Linklist<int> a(tempi); //创建模板类对象时一定要注明类型
a.Locate(tempi);
a.Insert(1); //参数为int类型
a.Insert(2);
cout <<"After Linklista Insert" <<endl;
a.Show();
cout <<"请输入一个字符:" <<endl;
cin >>tempc;
Linklist<char> b(tempc); //创建模板类对象时一定要注明类型
b.Locate(tempc);
b.Insert('C'); //参数为char类型
b.Insert('P');
cout <<"After Linklist b Insert" <<endl;
b.Show();
system("pause");
return 0;
}
//linklist.h
#include "node.h"
#include <iostream>
using namespace std;
template <class T> class Linklist
{
public:
Linklist(T a);
Linklist(Linklist<T> &l); //拷贝构造函数
~Linklist();
bool Locate(T a); //参数的数据类型由T决定
bool Insert(T a);
bool Delete();
void Show();
void Destroy();
private:
Node<T> head;
Node<T> * pcurrent;
};
//链表类模板的构造函数
template <class T> Linklist<T>::Linklist(T a):head(a)
{
cout <<"Linklist constructor is running..." <<endl;
pcurrent=&head;
}
template <class T> Linklist<T>::Linklist(Linklist<T> &l):head(l.head)
{
cout <<"Linklist Deep cloner running..." <<endl;
pcurrent=&head;
Node<T> * ptemp1=l.head.next; //创建模板类对象时一定要注明类型
while(ptemp1!=NULL) //逐一拷贝结点的data
{
Node<T> * ptemp2=new Node<T>(ptemp1->data,pcurrent,NULL);
pcurrent->next=ptemp2;
pcurrent=pcurrent->next;
ptemp1=ptemp1->next;
}
}
template <class T> Linklist<T>::~Linklist()
{
cout <<"Linklist destructor is running..." <<endl;
Destroy();
}
// 节点查找
template <class T> bool Linklist<T>::Locate(T a)
{
Node<T> * ptemp=&head;
while(ptemp!=NULL)
{
if(ptemp->data==a)
{
pcurrent=ptemp;
return true;
}
ptemp=ptemp->next;
}
return false;
}
// 节点插入
template <class T> bool Linklist<T>::Insert(T a)
{
if(pcurrent!=NULL)
{
Node<T> * temp=new Node<T>(a,pcurrent,pcurrent->next);//先连
if (pcurrent->next!=NULL)
{
pcurrent->next->prior=temp; //后断
}
pcurrent->next=temp; //后断
return true;
}
else
{
return false; //插入失败
}
}
template <class T> bool Linklist<T>::Delete()
{
if(pcurrent!=NULL && pcurrent!=&head)
{
Node<T> * temp=pcurrent;
if (temp->next!=NULL)
{
temp->next->prior=pcurrent->prior; //先连
}
temp->prior->next=pcurrent->next; //先连
pcurrent=temp->prior;
delete temp; //后断
return true;
}
else
{
return false;
}
}
template <class T> void Linklist<T>::Show()
{
Node<T> * ptemp=&head;
while (ptemp!=NULL) //链表的遍历
{
cout <<ptemp->data <<endl;
ptemp=ptemp->next;
}
}
template <class T> void Linklist<T>::Destroy()
{
Node<T> * ptemp1=head.next;
while (ptemp1!=NULL) //逐一删除结点对象
{
Node<T> * ptemp2=ptemp1->next;
delete ptemp1;
ptemp1=ptemp2;
}
head.next=NULL;
}
//node.h
#include <iostream>
using namespace std;
template <class T> class Linklist;
//如果要将一个类模板作为友元,必须声明它的存在
template <class T> class Node //定义一个链表结点类模板
{
friend class Linklist<T>; //链表类模板作为友元
public:
Node();
Node(Node<T> &n); //参数是一个模板类对象的引用,<T>不可缺少
Node(T a); //构造函数重载1
Node(T a,Node<T> *p,Node<T> *n); //构造函数重载2
~Node();
private:
T data; //成员数据的类型由类型参数T决定
Node<T> *prior;
Node<T> *next;
};
template <class T> Node<T>::Node()
{
cout <<"Node constructor is running..." <<endl;
prior=NULL;
next=NULL;
}
template <class T> Node<T>::Node(T a)
{
cout <<"Node constructor is running..." <<endl;
data=a;
prior=NULL;
next=NULL;
}
template <class T> Node<T>::Node(T a,Node<T> *p,Node<T> *n)
{
cout <<"Node constructor is running..." <<endl;
data=a;
prior=p;
next=n;
}
template <class T> Node<T>::Node(Node<T> &n)
{
data=n.data;
prior=n.prior;
next=n.next;
}
template <class T> Node<T>::~Node()
{
cout <<"Node destructor is running..." <<endl;
}
-End-