- 一、模板函数(compare)
- 1. 一般模板函数
- 2. 特化模板函数
- 3. 测试
- 4. 小结
- 二、模板类Queue或Stack
- 1. 模板类(Queue,Stack)
- 2. 成员模板函数
- 3. 模板特化:模板函数特化、模板成员函数特化、模板类特化
- 3.1. 模板函数特化
- 3.2. 模板成员函数特化
- 3.3. 模板类特化
- 4. 代码:
- queue.h
- queue.cpp
- Test.cpp
- 三、模板类AutoPtr
- 1. 构造函数
- 2. 析构函数
- 3. 拷贝构造函数
- 4. 等号、->、*等运算符重载
- 5. 主函数调用AutoPtr
- 6. 总结
首先写一个判断是否相等的模板函数,注意声明和函数体都写在头文件中。
//模板函数需要将声明和函数体都放在头文件中 //一般模板函数 template2. 特化模板函数bool compare(const T& a, const T& b) { return a == b; }
使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数。
此处,该函数无法针对字符串类型使用,则需特化模板函数。
//上述模板函数对于字符串比较无法使用,所以需要特化 //格式:template<>不用写类型 // 函数名<特化类型>(特化类型 参数1, 特化类型 参数2,...) //注意声明必须放在头文件中,实例化必须在cpp文件中 template<> bool compare(const char* const& a, const char* const& b);
template<> bool compare3. 测试(const char* const& a, const char* const& b) { return strcmp(a, b) == 0; }
#include#include"queue.h" using namespace std; int main() { const int a = 1; const int b = 1; const char* c = "qwe", * d = "asd"; cout << compare(a, b) << endl; cout << compare(c, d); }
运行结果:
一般特化函数格式
template< 模板参数表>
类型名 参数名(参数表)
{
函数体的定义
}
特化模板函数注意点
- 使用模板特化时,必须要先有基础的模板函数(就是上面第一个模板函数)
- 使用特换模板函数时格式有要求:
2.1. template 后直接跟<> 里面不用写类型
2.2. 函数名<特化类型>(特化类型 参数1, 特化类型 参数2 , …) 在函数名后跟<>其中写要特化的类型- 特化的函数的函数名,参数列表要和原基础的模板函数想相同,避免不必要的错误
- 声明必须放在头文件中,实例化必须在cpp文件中
函数模板与函数的区别
二、模板类Queue或Stack 1. 模板类(Queue,Stack)
- 函数模板本身在编译时不会生成任何目标代码,只有由模板生成的实例会生成目标代码。
- 被多个源文件引用的函数模板,应当连同函数体一同放在头文件中,而不能像普通函数那样只将声明放在头文件中。
- 函数指针也只能指向模板的实例,而不能指向模板本身。
类模板格式:
template<模板参数表>
class 类名
{
类成员声明
};
如类模板QueueItem
templateclass QueueItem { QueueItem(const Type &t) :item(t), next(0){} Type item; QueueItem * next; friend class Queue ; friend ostream& operator<<(ostream& os,const Queue &q); public: QueueItem * operator++() { return next; } Type & operator*() { return item; } };
模板参数表中参数可以声明为该模板类的友元类
如以上代码第6,7行的友元类
可通过typedef或者using对实例化的类模板定义别名
- 在类模板中直接声明然后实例化
- 如果需要在类模板以外定义其成员函数,则要采用以下的形式(现在类模板中声明成员函数):
template<模板参数表>
类型名 类名<模板参数标识符列表>::函数名(参数表){}
template3. 模板特化:模板函数特化、模板成员函数特化、模板类特化 3.1. 模板函数特化c1ass 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); }; template template void Queue ::assign(It beg,It end) { destroy(); copy_items(beg,end); }
模板函数特化见目录一、模板函数 2.特化模板函数
3.2. 模板成员函数特化头文件中声明
template<> void Queue::push(const char * const &val) ; template<> void Queue ::pop();
cpp文件中实现
template<> void Queue3.3. 模板类特化::push(const char * const &val) { char* new_item = new char[str1en(va1)+1]; strncpy(new_item, val, strlen(va1)+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 类名
{
类成员声明
};
//模板类特化
template<> //<>里为空
class 类名<特化类型> //<>里指明具体类型
{
类成员声明
};
4. 代码:
queue.h
#ifndef QUEUE_H #define QUEUE_H #includequeue.cppusing namespace std; //模板函数需要将声明和函数体都放在头文件中 //一般模板函数 template bool compare(const T& a, const T& b) { return a == b; } //上述模板函数对于字符串比较无法使用,所以需要特化 //格式:template<>不用写类型 // 函数名<特化类型>(特化类型 参数1, 特化类型 参数2,...) //注意声明必须放在头文件中,实例化必须在cpp文件中 template<> bool compare (const char* const& a, const char* const& b); template class Queue; template class QueueItem { QueueItem(const Type &t) :item(t), next(0){} Type item; QueueItem * next; friend class Queue ; friend ostream& operator<<(ostream& os,const Queue &q); public: QueueItem * operator++() { return next; } Type & operator*() { return item; } }; template class 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); }; template void 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=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; } } #endif // QUEUE_H
#include "queue.h" #includeTest.cpptemplate<> bool compare (const char * const &a, const char * const &b) { return strcmp(a,b) == 0; } 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; }
#include#include"queue.h" #include #include "autoptr.h" #include "CMatrix.h" using namespace std; int main() { //const int a = 1; //const int b = 1; //const char* c = "qwe", * d = "asd"; //cout << compare(a, b) << endl; //cout << compare(c, d); Queue qt; double d = 3.3; qt.push(1); qt.push(d); qt.push(10); cout << endl; cout << qt; short a[5] = { 0,3,6,9 }; Queue qi(a, a + 5); cout << endl; cout << qi; cout << endl; while (!qi.empty()) { cout << qi.front() << " "; qi.pop(); } vector vi(a, a + 5); qi.assign(vi.begin(), vi.end()); cout << endl; cout << qi; cout << endl; Queue q1; q1.push("hi"); q1.push("I'm"); q1.push("Jerry"); cout << q1; cout << endl; Queue q2(q1); cout << q2; //AutoPtr h1; //double data[6] = {1,2,3,4,5,6}; //h1->Create(2,3,data); //AutoPtr h2(h1); //(*h2).Set(0,1,10); //cout<<*h1<<*h2; }
运行结果:
函数声明
AutoPtr(T* pData);
函数实例化
template2. 析构函数AutoPtr ::AutoPtr(T* pData) { m_pData = pData; m_nUser = new int(1); }
~AutoPtr()
{
decrUser();
}
void decrUser();
template
void AutoPtr::decrUser()
{
--(*m_nUser);
if ((*m_nUser) == 0)
{
delete m_pData;
m_pData = 0;
delete m_nUser;
m_nUser = 0;
}
}
3. 拷贝构造函数
函数声明
AutoPtr(const AutoPtr& h);
函数实例化
template4. 等号、->、*等运算符重载AutoPtr ::AutoPtr(const AutoPtr & h) { m_pData = h.m_pData; m_nUser = h.m_nUser; (*m_nUser)++; }
AutoPtr5. 主函数调用AutoPtr& operator=(const AutoPtr & h); T* operator->() { return m_pData; } T& operator*() { return *m_pData; } const T& operator *()const { return *m_pData; } const T* operator ->()const { return m_pData; } template AutoPtr & AutoPtr ::operator=(const AutoPtr & h) { decrUser(); m_pData = h.m_pData; m_nUser = h.m_nUser; (*m_nUser)++; }
#include#include"queue.h" #include #include "autoptr.h" #include "CMatrix.h" using namespace std; int main() { //const int a = 1; //const int b = 1; //const char* c = "qwe", * d = "asd"; //cout << compare(a, b) << endl; //cout << compare(c, d); //Queue qt; //double d = 3.3; //qt.push(1); //qt.push(d); //qt.push(10); //cout << endl; //cout << qt; //short a[5] = { 0,3,6,9 }; //Queue qi(a, a + 5); //cout << endl; //cout << qi; //cout << endl; //while (!qi.empty()) //{ // cout << qi.front() << " "; // qi.pop(); //} //vector vi(a, a + 5); //qi.assign(vi.begin(), vi.end()); //cout << endl; //cout << qi; //cout << endl; //Queue q1; //q1.push("hi"); //q1.push("I'm"); //q1.push("Jerry"); //cout << q1; //cout << endl; //Queue q2(q1); //cout << q2; AutoPtr h1; double data[6] = {1,2,3,4,5,6}; h1->Create(2,3,data); cout << *h1 << endl; AutoPtr h2(h1); (*h2).Set(0,1,10); cout << *h1 << endl << *h2; }
运行结果如下:h2通过拷贝构造函数创建(拷贝h1),则h2调用Set方法后改变的是同一个地址的值,所以最后h1改变了,h1和h2输出结果相同。
在C++中,动态内存的管理是用一对运算符完成的:new和delete,new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,delete:指向一个动态独享的指针,销毁对象,并释放与之关联的内存。
动态内存管理经常会出现两种问题:一种是忘记释放内存,会造成内存泄漏;一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。
为了更加容易(更加安全)的使用动态内存,引入了智能指针的概念。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。



