模板类的继承(类模板作为基类),内嵌类的继承

在这里插入图片描述

对这道题目和我的数据结构课程致以最崇高的敬意。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

样例输入:

int main() {
    LinkedList<int> * list = new LinkedList<int>;
    LinkedList<int> * stack = new Stack<int>;
    LinkedList<int> * queue = new Queue<int>;

    cout << "LinkedList" << endl;
    list->pushFront(1);
    list->pushBack(2);
    list->pushBack(3);
    list->pushFront(4);
    list->print();
    list->popFront();
    list->popBack();
    list->print();
    cout << list->size() << endl;

    cout << stack->name() << endl;
    stack->push(1);
    stack->push(2);
    stack->push(3);
    stack->push(4);
    cout << stack->peak() << endl;
    stack->pop();
    cout << stack->pop() << endl;
    cout << stack->peak() << endl;

    cout << queue->name() << endl;
    queue->push(1);
    queue->push(2);
    queue->push(3);
    queue->push(4);
    cout << queue->peak() << endl;
    queue->pop();
    cout << queue->pop() << endl;
    cout << queue->peak() << endl;

    delete list;
    delete stack;
    delete queue;

    return 0;
}

样例输出:

LinkedList
4 1 2 3 
1 2 
2
Stack
4
3
2
Queue
1
2
3

在这里插入图片描述

AC代码:

#include<iostream>
#include<cstdio>
using namespace std;
		
template <class T>
class LinkedList{
	private:
		struct Node{
			T data;
			Node *next, *prev;
			Node(const T &x){
				data = x;
				next = NULL;
				prev = NULL; 
			}
		};
		
	protected:
		Node *head;
		Node *tail;
		int length;//c++11以后才可以初始化 
		void clear(){
			Node *p = head, *q;
			while(p){
				q = p->next;
				delete p;
				p = q;
				//p = p->next ;这样写也不对啊!!因为p也被删了没有next啊 
				//head = head->next ; 这样写绝对不对啊!!!你的head在前面已经被删了哪来的next 
				
			}
			length = 0;
			head = NULL;
			tail = NULL;
			//这里不清干净的话,派生类clear完了回到父类里面head和tail还有值,导致delete多了,出错 
		} 
	public:
		LinkedList(){
			head = NULL;
			tail = NULL;//还不涉及到插入特定位置,不太需要头尾结点
			length = 0;
		}
		void pushFront(T k){
			Node *tmp = new Node(k);
			tmp->next = head;
			if(head) head->prev = tmp;
			head = tmp;
			if(!tail) tail = head;
			length++;
		}
		void pushBack(T k){
			Node *tmp = new Node(k);
			tmp->prev = tail;
			if(tail) tail->next = tmp;
			tail = tmp;
			if(!head) head = tail;
			length++;
		}
		T popFront(){
			if(head){
				if(head==tail) tail = NULL;
				Node *tmp = head;
				head = head->next ;
				if(head) head->prev = NULL; //可以不写 
				 
				length--;
				T x = tmp->data ;
				delete tmp;
//				cout<<"pop"<<x<<endl; 测试用的输出记得删掉……
				return x;
			}
			else return T();
		}
		T popBack(){
		//注意!!!!当删到最后一个的时候,head=tail,如果只维护tail不管head会出错! 
			if(tail){
				if(head==tail) head = NULL;
				Node *tmp = tail;
				tail = tail->prev;
				if(tail) tail->next = NULL;
				//不维护tail怎么行…… 后路要截断 
				length--;
				T x = tmp->data;
				delete tmp;
//				cout<<"pop"<<x<<endl;
				return x;
			}
			else return T();
		}
		int size(){
			return length;
		}
		
		LinkedList(const LinkedList &x){
			Node *q = x.head;
			while(q){
				pushBack(q->data);
				q = q->next ; 
			}
			length = x.length;//不要写成q.length... 
		}
		void print(){
			Node *q = head;
			while(q){
				cout<<q->data <<" ";
				q = q->next;
			}
			cout<<endl;
		}
		virtual ~LinkedList(){
			clear();
		}
		virtual const char *name(){//虚函数在父类里面必须实现(如果你定义了父类或子类的对象) 
			
			return (char *)("LinkedList");
		}
		virtual T peak(){
			return head->data; 
		}
		virtual T pop() {
			return popFront();
		}
		virtual void push(T val){
			pushFront(val);
		}
		 
};

template <class T>
class Stack:public LinkedList<T>{
	public:
		const char *name(){
			return (char *)("Stack");
		}
		T peak(){
			return this->head->data; 
		}
		T pop(){
			return LinkedList<T>::popFront();
		}
		void push(T k){
			LinkedList<T>::pushFront(k);
			return;
		} 
		~Stack(){
//			cout<<"Stack clear"<<endl;
			LinkedList<T>::clear();
		}
};

template <class T>
class Queue:public LinkedList<T>{
	public:
		const char *name(){
			return (char *)("Queue");
		}
		T peak(){
			return LinkedList<T>::head->data; 
		}
		T pop(){
			return LinkedList<T>::popFront();
		}
		void push(T k){
			LinkedList<T>::pushBack(k);
			return;
		} 
		~Queue(){
//			cout<<"Queue clear"<<endl;
			LinkedList<T>::clear();
		}
};

本题反思:
1、类模板的写法!哪里加template?哪里加T
2、Node采用内嵌类的写法,成为LinkedList的private部分,内嵌类可以被继承,private继承的内嵌类自然无法访问,但protected和public是可以被继承的,在使用Node *p定义一个指针p的时候,要在前面加关键字typename(详情请见后续附上的实验)
3、Node类型的变量和指针其实没有必要被子类使用,因为可以在基类里面写好函数,子类直接调用就可以了(如clear())
4、Clear()写的时候要注意!!!不可以用已经被delete掉的变量再来->next,因为根本无法这样做啊啊啊!思路要清晰!遍历可以就一个指针不停往后跑因为没有删除操作,但是clear和pop必须定义两个指针,为了保证你删完了还找得到后续的结点,否则删完了就是删完了,后面也找不到了
5、注意子类调用析构函数结束后,是会调用父类的析构函数的!所以你在写clear的时候一定要把head和tail置为0,否则第二次析构的时候会再次析构一遍,导致RE!!(应该是RE吗)
6、注意popFront()popBack()!弹出结点的时候注意,只剩一个结点时的情况比其他更复杂一些!如果按照之前的操作,删头只改头,删尾只改尾,会导致删完头了tail还在,删完尾了head还在,导致“链删完后再压入,本该回到初始状态(head,tail都为0),但实际上却不一样了(有的不为0)”(如果你用length判断该链表是否为空,也许会更不容易出错一些,但是引入一个length进入考虑会增加思考的复杂程度(其实也不会))总之,再clear就完完全全地清空好了!回到原先的初始状态一模一样总不会出错
7、注意tail的维护!!!!特别是删了尾巴以后要加if(tail) tail->next=NULL;否则next还指着一个地址,输出的时候就会出错!
8、结构体指针要用->,不可以用.!!!
9、虚函数在父类里面必须实现啊!!(如果你根本没定义该父类或子类的对象,另当别论,因为它根本没实例化,自然不需要涉及这些语句)纯虚函数不需要实现。
10、类模板作为基类:注意二段式查找相关的理论!类模板作为基类,在实例化之前,它的子类并不知道自己继承了什么,所以会把父类的内部成员看作非成员,所以会显示你使用的东西没有被定义。解决方法是:使用指针this->f();或指明A<T>::f(); 根据资料,还可以写using A<T>::f();记得带上模板<T>
11、提交前还是检查下哈……该删的要删!免得罚时太多还搞得心里不停自我怀疑……
12、该自己造数据就快点造!比较好的习惯是:读题仔细,每一步想清楚,不清楚的写下来不要埋地雷,写下来后动手演示画图演算不要对着屏幕空想,样例过了自己造点数据测试一下,提交前检查也没有多余输出

其余实验及反思:
1、结构体Node不内嵌:放在外面,也是模板,全是public,使用时需要加上模板参数<T>
2、protected和public内嵌,以及类模板作为基类继承:
实验代码如下,实验结果如上所示

#include<iostream>
#include<cstdio>
using namespace std;

template<class T>
class A{
	public://或protected
	struct B{
		T data;
	};
	protected:
		T x;
};

template <class T> 
class C:public A<T>{
	A<T>::x; //可以编译但有warning 
	C:A<T>::x;//可以编译,无warning 
	//C():A<T>::x;//不可以编译 
	typename A<T>::B *p;//可以编译 
	//A<T>::B *p;不可以编译 
};

int main(){
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值