- 一、实验要求
- 1、模板函数(compare)
- 一般模板函数
- 特化模板函数
- 2、模板类Queue或Stack
- 模板类(Queue,Stack)
- 成员模板函数
- 模板特化:模板函数特化、模板成员函数特化、模板类特化
- 3、模板类AutoPtr
- 构造函数
- 析构函数
- 拷贝构造函数
- 等号、->、*等运算符重载
- 主函数调用AutoPtr
- 二、实验内容
- 1、模板函数(compare)
- 一般模板函数
- 特化模板函数
- 2、模板类Queue或Stack
- 模板类(Queue,Stack)
- 成员模板函数
- 模板特化:模板函数特化、模板成员函数特化、模板类特化
- 模板函数特化
- 模板成员函数特化
- 模板类特化
- 3、模板类AutoPtr
- 构造函数
- 析构函数
- 拷贝构造函数
- 等号、->、*等运算符重载
- 主函数调用AutoPtr
- 三、总结
templateint compare(const Type& v1,const Type& v2) { if(v1>v2) { return 1; } else if(v1 cout<运行结果:
根据实验结果可以看出,无论参数是int类型,float类型,还是char类型,compare函数都会根据传入的参数类型输出对应的结果,这就是模板函数的优势所在。
特化模板函数
模板函数针对仅参数类型不同的函数。使用模板时我们就不用考虑到涉及的参数类型,编写的代码可以与类型无关,不用针对不同的参数类型进行不同的修改,这就极大的提高了编写代码的效率。在模板函数中,template和class为关键字,并且形参不能为空,一旦声明了模板函数就可以使用形参名声明类中的成员函数和成员变量,即在该函数中使用内置类型的地方都可以使用模板形参名,在参数传递时,编译器会根据传入的参数类型进行实例化。函数声明:
template<> int compare(const char* const &v1,const char* const& v2); 函数实现:
template<> int compare(const char* const &v1,const char* const &v2) { return strcmp(v1,v2); } cout<运行结果:
2、模板类Queue或Stack 模板类(Queue,Stack)
特化模板函数即在实例化模板时,对特定的实参类型进行特殊处理,模板特化分为全特化和偏特化,但需要注意的是函数模板的特化只能全特化。
以compare模板函数为例,若实参为char指针时,则比较的为指针大小,而非指针指向内容的大小,因此我们就需要专门为char指针类型实参进行特殊化处理,即特化模板函数。这样在调用compare函数时就会调用特化模板,比较指针指向的内容大小。特化模板函数需要在相应的头文件中进行声明。函数的实现只能放在.cpp文件中。templateclass Queue { public: Queue():head(0),tail(0){} Queue(const Queue&q):head(0),tail(0) { copy_items(q); } template Queue(It beg,It end):head(0),tail(0){copy_items(beg,end);} template void assign(It beg,It end); Queue& operator = (const Queue&); ~Queue(){destroy();} Type& front(){return head->item;} const Type& front()const{return head->item;} void push(const Type&); void pop(); bool empty()const{return head==0;} friend ostream& operator<<(ostream& os,const Queue &q) { os<<"<"; QueueItem *p; for(p=q.head;p;p=p->next) { os< item<<" "; } os<<">"; return os; } const QueueItem * Head() const{return head;} const QueueItem * End() const{return (tail==NULL)?NULL:tail->next;} private: QueueItem *head; QueueItem *tail; void destroy(); void copy_items(const Queue &); template void copy_items(It beg,It end); }; 我们定义一个模板类Queue,如模板函数一样,template与class均为关键字。与普通类相比,模板类的效率大幅提高。
成员模板函数templatevoid Queue ::destroy() { while (!empty()) { pop(); } } template void Queue ::pop() { QueueItem *p=head; head=head->next; delete p; } template void Queue ::push(const Type& val) { QueueItem * pt=new QueueItem (val); if(empty()) { head=tail=pt; } else { tail->next=pt; tail=pt; } } template<> void Queue ::push(const char * const&val); template<> void Queue ::pop(); template void Queue ::copy_items(const Queue & orig) { for(QueueItem *pt = orig.head;pt;pt->next) { push(pt->item); } } template Queue & Queue ::operator=(const Queue& q) { destroy(); copy_items(q); } template template void Queue ::assign(It beg,It end) { destroy(); copy_items(beg,end); } template template void Queue ::copy_items(It beg,It end) { while(beg!=end) { push(*beg); ++beg; } } 成员模板函数与模板函数类似,只是成员模板函数为模板类的成员函数,在声明了模板类之后,我们就可以用形参名声明类中的成员函数和成员变量。类模板中的成员模板函数在实现的时候需要加两个模板头,类模板头和成员模板头
模板特化:模板函数特化、模板成员函数特化、模板类特化 模板函数特化函数声明:
template<> int compare(const char* const &v1,const char* const& v2); 函数实现:
template<> int compare(const char* const &v1,const char* const &v2) { return strcmp(v1,v2); } cout< 运行结果:
特化模板函数即在实例化模板时,对特定的实参类型进行特殊处理,模板特化分为全特化和偏特化,但需要注意的是函数模板的特化只能全特化。
模板成员函数特化
以compare模板函数为例,若实参为char指针时,则比较的为指针大小,而非指针指向内容的大小,因此我们就需要专门为char指针类型实参进行特殊化处理,即特化模板函数。这样在调用compare函数时就会调用特化模板,比较指针指向的内容大小。特化模板函数需要在相应的头文件中进行声明。函数的实现只能放在.cpp文件中。template<> void Queue::push(const char* const &val) { char* new_item = new char[strlen(val)+1]; strncpy(new_item,val,strlen(val)+1); QueueItem * pt=new QueueItem (new_item); if(empty()) { head=tail=pt; } else { tail->next=pt; tail=pt; } } template<> void Queue ::pop() { QueueItem * p = head; delete head->item; head=head->next; delete p; } 与模板函数特化一样,模板成员函数特化也是对特定的实参类型进行特殊化处理。
模板类特化template<>class Queue{ public: void push(const char * str){real_queue.push(str);} void pop(){real_queue.pop();} bool empty()const {return real_queue.empty();} string front(){return real_queue.front();} const string &front()const{return real_queue.front();} private: Queue real_queue; }; 模板类特化划分为全特化和偏特化。全特化是模板的一个唯一特例,指定的模板实参列表必须和相应的模板参数列表一一对应。即明确所有模板实现的具体类型。偏特化即明确部分的类型。类模板支持全特化和偏特化,而函数模板只有全特化没有偏特化。
3、模板类AutoPtr在用new和delete管理动态内存时,容易出现忘记释放内存造成内存泄露问题以及在还有指针引用内存的情况下释放内存造成产生引用非法内存的指针问题,因此为了更加安全的使用动态内存,我们引入了智能指针。智能指针与普通指针的区别在于智能指针可以自动释放指针所指向的对象。
构造函数template析构函数AutoPtr ::AutoPtr(T* pData) { m_pData=pData; m_nUser=new int(1); } template拷贝构造函数void AutoPtr ::decrUser() { --(*m_nUser); if((*m_nUser)==0) { delete m_pData; m_pData=0; delete m_nUser; m_nUser=0; } } template等号、->、*等运算符重载AutoPtr ::AutoPtr(const AutoPtr & h) { m_pData=h.m_pData; m_nUser=h.m_nUser; (*m_nUser)++; } templateAutoPtr & AutoPtr ::operator=(const AutoPtr & h) { decrUser(); m_pData=h.m_pData; m_nUser=h.m_nUser; (*m_nUser)++; } T * operator->() { return m_pData; } T& operator*() { return *m_pData; } const T& operator *() const { return *m_pData; } const T* operator ->() const { return m_pData; }主函数调用AutoPtr#include "AutoPtr.h" #include "CMatrix.h" void TestAutoPtr() { AutoPtrh1(new CMatrix()); double data[6]={1,2,3,4,5,6}; h1->Create(2,3,data); cout<<*h1< h2(h1); (*h2).set(0,0,10); cout<<*h1<<*h2; } #include#include #include "canimal.h" //using namespace std; #include "person.h" #include "queue.h" #include using namespace std; int main() { void TestAutoPtr(); TestAutoPtr(); } 运行结果:
三、总结
h1创建了一个矩阵,h2通过拷贝构造函数创建了一个与h1相同的矩阵,在调用set方法后,h1与h2的矩阵都被修改,因此输出的矩阵结果相同。模板函数针对仅参数类型不同的函数。使用模板可以极大的提高编写代码的效率。模板函数的形参不能为空,一旦声明了模板函数就可以使用形参名声明类中的成员函数和成员变量。
模板特化分为全特化和偏特化,但需要注意的是类模板支持全特化和偏特化,函数模板的特化只能全特化。
特化模板函数需要在相应的头文件中进行声明。函数的实现只能放在.cpp文件中。
智能指针与普通指针的区别在于智能指针可以自动释放指针所指向的对象。



