- 一、实验内容
- 二、代码实现
- 1.queue.h
- 2.queue.cpp
- 3.main.cpp
- 4.实验结果
- 三、知识点总结
- 1.模板的特化
- 2.模板函数
- 3.类模板
- 4.const type& 与 type& 的区别
- 5.operator<<>>运算符重载一定要为友元函数
1.模板函数(compare)
一般模板函数
特化模板函数
2、模板类Queue或Stack
模板类(Queue,Stack)
成员模板函数
模板特化:模板函数特化、模板成员函数特化、模板类特化
3、模板类AutoPtr
构造函数
析构函数
拷贝构造函数
等号、->、*等运算符重载
主函数调用AutoPtr
#ifndef QUEUE_H #define QUEUE_H #include2.queue.cpp#include using namespace std; //类模板:用于生成类 template class queue; template class queueItem; template class queueItem { Type item; queueItem* next; queueItem(const Type& t) :item(0), next(0) {} friend class queue ; //友元类,目的访问这里面的私有成员 friend ostream& operator<<(ostream& os, const queue & q); public: queueItem * operator++() { //重载运算符++ 用于指向队列里的下一个元素(指针类型) return next; } Type& operator*() { //重载运算符* 用于取队列里对应指针的值(取地址后 是Type类的) 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&); void push(const Type&); //https://www.cnblogs.com/wss-is-knight/p/3624164.html void pop(); bool empty() const { return head == 0; } ~queue() { //析构函数 destory(); } Type& front() {//取队列头指针的值(取地址符) return head->item; } const Type& front() const { //返回值不能修改,并且不能修改对应对象中成员函数的值~ return head->item; } friend ostream& operator<<(ostream& os, const queue & q) { //https://blog.csdn.net/qq_36864672/article/details/76422722 os << "<"; queueItem * p; for (p = q.head; p; p = p->next) { os << p->item << " "; } os << ">"; return os; } const queueItem * Head()const { return head; } const queueItem * End() const {//const no.1:避免返回值被修改 no.2:表示在函数内不能改变其对应对象的成员变量的值 return (tail == NULL) ? NULL : tail->next; } //void copy_items(const queue &); private: queueItem * head; queueItem * tail; void destory(); void copy_items(const queue&); template void copy_items(It beg, It end); }; template void queue ::destory() { while (!empty()) { pop(); } } template void queue ::pop() { queueItem * p = head; head = head->next; //head虽然是私有变量,但是有friend升级 delete p; } template void queue ::push(const Type& val) { queueItem * pt = new queueItem (val);//初始化并赋初值 pt->item = val; if (empty()) { head = tail = pt; //cout << "success1" << endl; } else { tail->next = pt; tail = pt; //cout << "success2" << endl; } } template queue & queue ::operator=(const queue& q) { destory(); copy_items(q); } template int compare(const Type& v1, const Type& v2) { if (v1 < v2) return -1; else if (v1 > v2) return 1; return 0; } template template void queue ::assign(It beg, It end) { destory(); copy_items(beg, end); } template template void queue ::copy_items(It beg, It end) { while (beg != end) { push(*beg); ++beg; } } template void queue ::copy_items(const queue& orig) { for (queueItem * pt = orig.head; pt; pt = pt->next) { push(pt->item); } } template < > void queue ::push(const char* const& val); template < > void queue ::pop(); template < > int compare (const char* const& v1, const char* const& v2); #endif // QUEUE_H
#include "queue.h" #include3.main.cpptemplate<> //对模板函数的特化 int compare (const char* const& v1, const char* const& v2) { return strcmp(v1, v2);//因为字符串类型的不能直接==比较,所以需要特化一下~ } 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; }
#pragma once #include "queue.h" #include4.实验结果 三、知识点总结 1.模板的特化void TestQueue() { 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; vector vi(a, a + 5); qi.assign(vi.begin(), vi.end()); cout << endl; cout << qi; queue q1; q1.push("hi"); q1.push("I'm"); q1.push("fffffdy"); cout << endl; cout << q1; queue q2(q1); cout << q2; } int main() { TestQueue(); return 0; }
函数模板特化:使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数(就是写出一个模板函数专门给该类型使用),比如:
template<> //对模板函数的特化 int compare(const char* const& v1, const char* const& v2) { return strcmp(v1, v2);//因为字符串类型的不能直接==比较,所以需要特化一下~ }
【注意】
*使用模板特化时,必须要先有基础的模板函数(就是上面第一个模板函数)
*使用特换模板函数时格式有要求:
1.template 后直接跟<> 里面不用写类型
2.函数名<特化类型>(特化类型 参数1, 特化类型 参数2 , …) 在函数名后跟<>其中写要特化的类型
*特化的函数的函数名,参数列表要和原基础的模板函数想相同,避免不必要的错误
*如果有能匹配的函数,则先使用特化函数
类模板特化:
全特化: 即将所有的模板类型都进行特化
偏特化:对于模板的类型做一些限制
a.部分特化:就是只对函数模板的一部分模板类型进行特化
b.对类型的范围的限制,主要的类型基础不变
templateclass Test{ } //全特化 template <> //此处同函数模板的特化一样不用写内容 class Test { } template class Test2{ } //部分特化 template //此处只需写未进行特化的模板类型,特化过的就不用写 class Test2 { } template class Test2{ } //对模板类型的范围做出一定的限制 template //此处只需写未进行特化的模板类型 class Test2 { }
类的成员模板函数的特化:
template < > void queue2.模板函数::push(const char* const& val); template < > void queue ::pop();
用于生成函数的
面向对象的继承和多态机制有效提高了程序的可重用性和可扩充性。在程序的可重用性方面,程序员还希望得到更多支持。就比如说写那个compare函数的时候,因为比较类型的不同(int,double,short等等)所以就需要写很多个重复的函数,这时候引入模板函数就很方便了~提高代码可读性!
有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,这个时候设计类模板就比较好用~
单个类模板:
1 //类的类型参数化 抽象的类 2 //单个类模板 3 template4 class A 5 { 6 public: 7 A(T t) 8 { 9 this->t = t; 10 } 11 12 T &getT() 13 { 14 return t; 15 } 16 protected: 17 public: 18 T t; 19 }; 20 void main() 21 { 22 //模板了中如果使用了构造函数,则遵守以前的类的构造函数的调用规则 23 A a(100); 24 a.getT(); 25 printAA(a); 26 return ; 27 }
继承的类模板:
1 #include4.const type& 与 type& 的区别2 using namespace std; 3 //A编程模板类--类型参数化 4 7 template 8 class A 9 { 10 public: 11 A(T a = 0) 12 { 13 this->a = a; 14 } 15 public: 16 void printA() 17 { 18 cout << "a:" << a << endl; 19 } 20 protected: 21 private: 22 T a; 23 }; 24 //参数 C++编译器具体的类 25 void UseA(A &a) 26 { 27 a.printA(); 28 } 29 void main() 30 { 31 //模板类本身就是抽象的,具体的类,具体的变量 32 A a1(11),a2(22),a3(33);//模板类是抽象的, 需要类型具体化 33 //a1.printA(); 34 35 UseA(a1); 36 UseA(a2); 37 UseA(a3); 38 }
(1.int& 讲解
a的值可以通过a改变,也可以通过b改变
int a = 10; int& b = a;
(2.const int& 讲解
a的值只能通过a改变,不能通过b改变
int a = 10; const int& b = a;
(3.const int a = value 的引用只能为 const int b& = a
因为a的值是无法改变的,所以其引用也无法改变a的值,所以只能为常引用
如果是重载双目操作符(即为类的成员函数),就只要设置一个参数作为右侧运算量,而左侧运算量就是对象本身。
而 >> 或<< 左侧运算量是 cin或cout 而不是对象本身,所以不满足后面一点,嗯。。。就只能申明为友元函数了~
https://www.cnblogs.com/wss-is-knight/p/3624164.html
https://blog.csdn.net/low5252/article/details/94622335
https://www.cnblogs.com/hailong/articles/1977370.html
https://blog.csdn.net/alzzw/article/details/108150358
https://blog.csdn.net/qq_36864672/article/details/76422722



