队列(queue) 之 c++模板实现(友元函数和运算符重载)
来源:互联网 发布:淘宝布衣柜 编辑:程序博客网 时间:2024/05/16 12:46
一:起因(请参考c++中的悬浮指针和野指针 二级指针)
(0)拿出自己年初实现的queue队列,第一次用c++类实现queue,在和如今实现的其他复杂的STL对比,心情无比复杂;
注释:看到听到当年自己的所写所想,正的是一种享受 —— 倾听自己的幼稚也是一种美。
(1)闲话少说了,我自己现在回答自己的 三 (5) 中提到的问题,函数的返回值是用bool型还是void型??其实函数返回值是bool 还是 void是视情况而定的:例如,判空函数bool isEmpty(),比较运算符重载函数 bool operator >=(&)等判断函数; 而像交换swap(&,&),清空clear(),insert(),delete(),push,pop等一般void就可以了。
(2)再有就是是通过函数返回值返回值,还是通过参数的应用返回值呢? 仍是视情况而定的,如果返回多值,只能通过参数了;下面说一说返回单值的情况,多数是通过函数返回值返回的只有像swap(&,&) (类成员函数就一个参数的哦,默认有一个隐含的this指针),reverse()等。
(3)现在的问题是 返回单值 时是引用型(&) 还是 返回临时变量的值的形式? 第一,如果返回值的参数是该子函数的局部变量,只能以临时变量的形式返回;第二,如果在该子函数中,返回值的参数是类的成员变量(私有或共有),或者说是全局变量,可以返回引用。但是返回引用是有风险的 如,T& front(){return head->data;} 在主函数中是可以联动修改数据值的。
(4)再说const 如函数friend MyString operator+(const MyString& t1,const MyString& t2); 说明t1 t2 是不可改变的应用参数,即其作为引用仅仅是为了减少开销,并不是作为函数返回值用的,其返回值类型是MyString类型(非引用),说明返回的是函数的局部参数。
(5)再看此函数 const int &operator[](const size_t)const;
第一个const说的是返回值,返回的是一个常量引用,不能修改;第二个const是一个参数,表示在函数内不会修改这个参数;最后一个const是表示this指针指向的是const也就是在这个函数内,这个类所有成员都相当于是const。
第三个const 还参与对重载函数的区分,这样在参数类型个数相同的情况下形成一种新的重载形式。需要注意:常成员函数是常对象唯一的对外接口,使用使应该注意。常成员函数不能更新对象的数据成员,也不能调用该类中的普通成员函数。
(6)友元类,不多说了,请看示例吧
假设我们要设计一个模拟电视机和遥控器的程序。大家都之道,遥控机类和电视机类是不相包含的,而且,遥控器可以操作电视机,但是电视机无法操作遥控器,这就比较符合友元的特性了。即我们把遥控器类说明成电视机类的友元。下面是这个例子的具体代码:#include <iostream>usingnamespacestd;classTV{public:friendclassTele;TV():on_off(off),volume(20),channel(3),mode(tv){}(7)说明了一点,我也曾经幼稚过,现在还比较幼稚,但我相信,只要坚持最初梦想的人,终究会走向成熟;
(8)再次感谢自己能坚持最初的梦,相信你也有一个类似的梦;不要羡慕别人天赋,别人的成功是无法复制的,别人的辉煌是不会重演的;唯有我们自己脚踏实地的走好每一步,播下我们自己梦想的种子,大步向前。
二:代码展现
(1)queue队列类
#include <iostream>using namespace std;template<typename T> class queue;template<typename T>class queue_item{ friend class queue<T>; queue_item(const T &i):item(i),next(0){}// next的默认值 T item; queue_item *next;};// 和 struct类似的哦,当然也可以改为struct的哦template<typename T>class queue{ public: queue():head(0),tail(0),n(0){}// ==0必须得有,head tail的初值要不要? queue(const queue &q); queue &operator= (const queue &q); ~queue(); void push(const T &key); void pop(); bool front(T &item); bool back(T &item); bool is_empty(){ return n == 0; } size_t size() { return n; } void clear(); private: queue_item<T> *head; queue_item<T> *tail;// queue_item没有默认构造函数,不知道为何可以这样声明;因为他是指针,只分配指针大小的内存,不分配对象内存的 size_t n; void copy_item(const queue &q);};// 队尾加入元素template<typename T>void queue<T>::push(const T &key){ queue_item<T> *item = new queue_item<T>(key); if(n == 0) head = tail = item; else { tail->next = item;// head指向队首元素 tail = tail->next;// tail指向刚刚进入的节点 } n++;}// 删除队首元素template<typename T>void queue<T>::pop(){ if(n == 0) return; else { queue_item<T> *tmp = head; head = head->next; delete tmp; n--; } return;}//返回队首元素template<typename T>bool queue<T>::front(T &item){ if(n == 0) return false; else item = head->item; return true;}//返回队尾元素template<typename T>bool queue<T>::back(T &item){ if(n == 0) return false; else item = tail->item; return true;}template<typename T>void queue<T>::clear(){ //if(n == 0) return false; while(n > 0) { pop(); } //return true;}//复制构造函数template<typename T>queue<T>::queue(const queue &q):head(0),tail(0),n(0){ copy_item(q);}// 析构函数template<typename T>queue<T>::~queue(){ clear();}//运算符重载函数template<typename T>queue<T> &queue<T>::operator = (const queue &q){ if(this != &q) { clear(); n = 0; copy_item(q); } return *this;}// 深度复制函数template<typename T>void queue<T>::copy_item(const queue &q){ queue_item<T> *tmp = q.head; while(tmp != NULL) { push(tmp->item); tmp = tmp->next; }}(2)main函数测试
#include <cstdlib>#include <iostream>#include <string>using namespace std;// test the queue class templateint main(int argc, char *argv[]) {queue<int> q;int front,back;if (q.is_empty())cout << "empty" << endl;elsecout << "not empty" << endl;q.push(1);q.push(2);q.push(3);q.push(4);queue<int> q2(q);q.clear();if (q.is_empty())cout << "empty" << endl;elsecout << "not empty" << endl; q2.front(front); q2.back(back);cout << "queue 2: " << front << endl;cout << "queue 2: " << back << endl;cout << "the size of queue 2: " << q2.size() << endl;q = q2;q.front(front); q.back(back);cout << "queue 1: " << front << endl;cout << "queue 1: " << back << endl;queue<string> qs;qs.push("gauss");qs.push("randy");qs.push("jiawenjie");string s1,s2;qs.front(s1);qs.back(s2);cout << s1 << endl;cout << s2 << endl;return EXIT_SUCCESS;}三:体会和总结
1、如果一个类中定义了任何一种构造函数,而未定义默认构造函数,是不能够定义类的对象的如:class A{}; A aa;(这是错误的)
但是A *pa;(这是合法的,因为仅仅定义了一个指针,没有调用任何构造函数,不分配类对象的内存)
2、类的private和protected成员是不能被类外访问,但是,此规则不影响friend(友元),如果我们想声明一个外部函数作为类的
friend(友元),从而使此函数访问这类的private和protected成员,我们通过这个外部函数的原型声明在类体里,前面加上关键字friend.
3、将A类声明为B类的友元(朋友),此时A类就是B类的友元类,友元类A的所有函数都是B类的友元函数,可以访问B类的所有私有成员
变量,但不等于B类是A类的友元类,B类的成员函数不能访问A类的私有成员变量.
4 、运算符重载一般也声明为友元函数(friend),
5、现在还有两点不是很明白,请大牛指点——函数的返回值是用bool型还是void型??再有就是是通过函数返回值返回值,还是通过参数的应用返回值呢?
- 队列(queue) 之 c++模板实现(友元函数和运算符重载)
- 队列(queue) 之 c++模板(友元函数和运算符重载)
- 重载运算符之友元函数和成员函数
- 运算符重载和友元函数
- 友元函数和运算符重载
- 运算符重载和友元函数
- (1.1.25)运算符重载和友元函数
- 函数模板和友元重载运算符报"无法解析的外部符"的解决方法
- 如何在类模板中重载输入输出运算符和友元函数
- C++实现输入输出运算符重载、友元函数和成员函数实现复数类Complex
- 【c++】关于类继承运算符重载友元函数
- 成员函数和友元函数实现一元运算符重载
- 友元函数实现复数类中的运算符重载
- 实现复数类中的友元函数运算符重载
- 利用友元函数实现对运算符的重载
- 友元函数实现复数中的运算符重载
- 实现复数类中的运算符重载 友元函数
- C++Primer Plus 第十一章-运算符重载和友元函数
- 黑马程序员——多线程2:应用
- VirtualBox内Linux系统怎样与Windows共享文件夹
- HDU_4001_To miss our children time_动态规划
- 循环综合题分析
- IHERB上待产包准备指南-妈妈篇
- 队列(queue) 之 c++模板实现(友元函数和运算符重载)
- javascript的总结
- 关于掩码
- POJ 2516 Minimum Cost (最小费用最大流)
- flash脚本程序编写技巧总结
- 请大神帮我解释一下一个oc的问题
- Unity3D之for循环题目
- LVM (Logical Volume Manager)的优势
- UVA - 624 CD (01背包)