C++ 代码重用 03-- 链表使用例程 类的包含与继承

80 篇文章 0 订阅
#include <iostream>
using namespace std;
/*---------------------------------
链表使用例程
第19章代码重用 : 19.15~21.图书药品管理系统 19.24.包含与继承
1)date类只负责存放数据
2)node类只用来创建和操作节点
3)list类只用来创建和操作链表
4)Repair类只用来管理链表对象和显示程序主界面
注意:
1)派生类要继续派生时,最好使用公有继承。
2)假如不想让派生类访问基类的某个或某些成员时,不要使用公有继承,而应该使用
   私有继承。
3)假如你在一个类中需要访问另一个类的多个对象时,必须使用包含,而不能
   使用私有继承。
4)假如你想根据一个已有的类定义另一个类,并且希望在该类中可以访问已有类的
   保护成员,那么请从已有类中派生此类,假如你只是想访问已有类的公有成员,不
   想访问该类的保护成员,那么请使用类的包含。


---------------------------------*/
class date
{
public:
	date(int num,float prc):number(num),price(prc)
	{cout<<"构造date..."<<endl;}
	float GetPrice()const{return price;}
	int   GetNumber()const{return number;}
	virtual void print()const=0;
	virtual ~date(){}
private:
	int number;
	float price;
};
class book:public date
{
public:
	book(int num,float prc):date(num,prc) //子类的构造函数,初始化传递参数给父类的构造函数
	{cout<<"构造book..."<<endl;}
	virtual void print()const
	{
		cout<<"图书的编号:"<<GetNumber()<<endl;
		cout<<"图书的价格:"<<GetPrice()<<endl;
	}
private:
};
class drug:public date
{
public:
	drug(int num,float prc):date(num,prc) //子类的构造函数,初始化传递参数给父类的构造函数
	{cout<<"构造drug..."<<endl;}
	virtual void print()const
	{
		cout<<"药品的编号:"<<GetNumber()<<endl;
		cout<<"药品的价格:"<<GetPrice()<<endl;
	}
private:
};
class node
{
public:
	node(date* pdate):itsdate(pdate),itsnext(0){}
	~node(){delete itsdate;itsdate=0;} //销毁对象数据
	void SetNext(node* no){itsnext=no;}//记住下一个节点的地址
	node* GetNext()const{return itsnext;}
	date* Getdate()const
	{
		if(itsdate)
		{  return itsdate;}
		else
		{  return NULL;}
	}
private:
	date* itsdate;
	node* itsnext;
};
class list
{
public:
	list():head(0),count(0){}
	~list();
	date* GetFirst()const;
	date* operator[](int offset)const;
	void show()const;
	int GetCount()const{return count;}
	void Insert(date*);
	void Delete(int num);
	date* Find(int num)const;
	date* Find(int& place,int num)const;
private:
	node* head;
	int count;
};
list::~list()
{
	node* l=head;
	node* m=0;
	int n=0;
	while(l)
	{
		m=l;
		l=l->GetNext();
		delete m;	
		n++;
		cout<<"删除第"<<n<<"个节点"<<endl;
	}
}
date* list::GetFirst()const
{
	if(head)
	{  return head->Getdate();}
	else
	{  return NULL;}
}
date* list::operator[](int offset)const
{
	node* pn=head;
	if(!head)
	{  return NULL;}
	if(offset>=count)
	{  return NULL;}
	for(int i=0;i<offset;i++)
	{
		pn =pn->GetNext();
	}
	return pn->Getdate();
}
void list::show()const
{
	if(!head)
	{  return;}
	node* pn=head;
	do{
		pn->Getdate()->print();//获取节点数据对象的地址后,打印相关数据
		pn=pn->GetNext();
	}while(pn);
}
void list::Insert(date* pdate)
{
	node* pn=new node(pdate);
	node* pnow=head;
	node* pnext=0;
	int num=pdate->GetNumber();
	if(!pnow)
	{
		head=pn;
		count=1;
		return;
	}
	count++;
#if 0
	//头部插入
	pnext=head->GetNext();
	pn->SetNext(pnext);
	head->SetNext(pn);
#else
	//升序插入
	if(head->Getdate()->GetNumber() > num)
	{
		pn->SetNext(head);
		head=pn;
		return;
	}
	else
	{
		pnext=head->GetNext();
		pnow=head;
		while(pnext)
		{			
			if(pnext->Getdate()->GetNumber() > num)
			{
				pnow->SetNext(pn);
				pn->SetNext(pnext);
				return;
			}
			else
			{
				pnow=pnext;
				pnext=pnext->GetNext();
			}
		}
		pnow->SetNext(pn);
		return;
	}
#endif
}
void list::Delete(int num)
{
	node* pback=head;
	node* pnow=head;
	if(!head)
	{
		cout<<"没有数据可删除"<<endl;
	}
	else
	{
		while(pnow)
		{
			if(num==pnow->Getdate()->GetNumber())
			{
				pback->SetNext(pnow->GetNext());
				if(pnow==head)//特别注意,如果是边界节点的情况
				{
					head=head->GetNext();
					cout<<"删除头结点"<<endl;
				}
				delete pnow;
				pnow =NULL;
				count--;
				cout<<"删除成功"<<endl;
				return;
			}
			else
			{
				pback=pnow;
				pnow=pnow->GetNext();
			}
		}
		cout<<"没有该数据,无法删除!"<<endl;
	}
}
date* list::Find(int num)const
{
	node* pn=0;
	for(pn=head;pn!=NULL;pn=pn->GetNext())
	{
		if(pn->Getdate()->GetNumber()==num)
			break;
	}
	if(pn==NULL)
		return NULL;
	else
		return pn->Getdate();
}
date* list::Find(int& place,int num)const
{
	node* pn=0;
	for(pn=head;pn!=NULL;pn=pn->GetNext(),place++)
	{
		if(pn->Getdate()->GetNumber()==num)
			break;
	}
	if(pn==NULL)
		return NULL;
	else
		return pn->Getdate();
}


#if 1
/*
19.23.利用私有继承来实现代码重用
1)包含和私有继承的区别:
	包含是将一个已命名的对象添加到类的私有部分中,而私有继承则是将一个未
	命名的对象(this对象)添加到类的私有部分中。
*/
class Repair:private list
{
public:
	void RInsert(date* newdate);
	void Run();
private:	
};
void Repair::RInsert(date* newdate)
{
	int number=newdate->GetNumber();
	int place=0;
	if(Find(place,number))
	{  cout<<"您输入的编号"<<number<<"与链表中第"<<place<<"个节点的编号重复"<<endl;}
	else  //为空,没找到,则插入
	{  Insert(newdate);}
}
void Repair::Run()
{
	date* pdate=0;
	int number;
	float price;
	int choice;
	bool quit=false;
	while(1)
	{
		//system("cls");
		cout<<"1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出"<<endl;
		cin>>choice;		
		switch(choice)
		{
		case 1:
			while(1)
			{
				cout<<"0)返回 1)图书 2)药品:";
				cin>>choice;
				if(!choice)
				{  break;}
				else if(1==choice||2==choice)
				{
					cout<<"请输入编号:";
					cin>>number;
					if(1==choice)
					{
						cout<<"请输入图书价格:";
						cin>>price;
						pdate=new book(number,price);
						RInsert(pdate);
					}
					else if(2==choice)
					{
						cout<<"请输入药品价格:";
						cin>>price;
						pdate=new drug(number,price);
						RInsert(pdate);
					}
					else
					{  cout<<"请输入0到2之间的数字!"<<endl;}
				}
			}
			break;
		case 2:
			if(GetFirst()==0)
			{  
				cout<<"您的商品为空,请增加商品\n按回车键返回";
				cin.get();
				cin.get();
			}
			else
			{
				show();
				cout<<"请按回车键返回主界面"<<endl;
				cin.get(); cin.get();
			}
			break;
		case 3:
			cout<<"请输入您要删除的商品编号:"<<endl;
			cin>>number;
			Delete(number);
			cin.get(); cin.get();
			break;
		case 4:
			while(1)
			{
				cout<<"0)返回 1)按编号查询 2)按序号查询:";
				cin>>choice;
				if(!choice)
				{  break;}
				else if(1==choice||2==choice)
				{										
					if(1==choice)
					{
						cout<<"请输入要查询的编号:";
						cin>>number;
						date* result=Find(number);
						if(NULL==result)
						{  cout<<"找不到该编号的商品"<<endl;}
						else
						{  result->print();}
					}
					else if(2==choice)
					{
						cout<<"请输入要查找的序号(链表的节点脚标号):";
						cin>>number;
						if((*this)[number]) //用"*"读取this指针指向的this对象
						{  (*this)[number]->print();}//与类的包含不同,类的私有继承需
						else					//要在这里显示地注明调用下标运算符的对象
						{  cout<<"找不到该序号的商品"<<endl;}


					}
					else
					{  cout<<"请输入0到2之间的数字!"<<endl;}
				}
			}
			break;
		case 5:
			cout<<"该链表共有"<<GetCount()<<"个节点"<<endl;
			break;
		case 6:
			quit=true;
			break;
		default:		break;
		}
		if(quit)
		{
			cout<<"程序结束"<<endl;
			break;
		}
	}	
}
#else
/*19.22.利用类的包含来实现代码重用*/
class Repair
{
public:
	void RInsert(date* newdate);
	void Run();
private:
	list pl;//类的包含
};
void Repair::RInsert(date* newdate)
{
	int number=newdate->GetNumber();
	int place=0;
	if(pl.Find(place,number))
	{  cout<<"您输入的编号"<<number<<"与链表中第"<<place<<"个节点的编号重复"<<endl;}
	else  //为空,没找到,则插入
	{  pl.Insert(newdate);}
}
void Repair::Run()
{
	date* pdate=0;
	int number;
	float price;
	int choice;
	bool quit=false;
	while(1)
	{
		//system("cls");
		cout<<"1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出"<<endl;
		cin>>choice;		
		switch(choice)
		{
		case 1:
			while(1)
			{
				cout<<"0)返回 1)图书 2)药品:";
				cin>>choice;
				if(!choice)
				{  break;}
				else if(1==choice||2==choice)
				{
					cout<<"请输入编号:";
					cin>>number;
					if(1==choice)
					{
						cout<<"请输入图书价格:";
						cin>>price;
						pdate=new book(number,price);
						RInsert(pdate);
					}
					else if(2==choice)
					{
						cout<<"请输入药品价格:";
						cin>>price;
						pdate=new drug(number,price);
						RInsert(pdate);
					}
					else
					{  cout<<"请输入0到2之间的数字!"<<endl;}
				}
			}
			break;
		case 2:
			if(pl.GetFirst()==0)
			{  
				cout<<"您的商品为空,请增加商品\n按回车键返回";
				cin.get();
				cin.get();
			}
			else
			{
				pl.show();
				cout<<"请按回车键返回主界面"<<endl;
				cin.get(); cin.get();
			}
			break;
		case 3:
			cout<<"请输入您要删除的商品编号:"<<endl;
			cin>>number;
			pl.Delete(number);
			cin.get(); cin.get();
			break;
		case 4:
			while(1)
			{
				cout<<"0)返回 1)按编号查询 2)按序号查询:";
				cin>>choice;
				if(!choice)
				{  break;}
				else if(1==choice||2==choice)
				{										
					if(1==choice)
					{
						cout<<"请输入要查询的编号:";
						cin>>number;
						date* result=pl.Find(number);
						if(NULL==result)
						{  cout<<"找不到该编号的商品"<<endl;}
						else
						{  result->print();}
					}
					else if(2==choice)
					{
						cout<<"请输入要查找的序号(链表的节点脚标号):";
						cin>>number;
						if(pl[number])
						{  pl[number]->print();}
						else
						{  cout<<"找不到该序号的商品"<<endl;}


					}
					else
					{  cout<<"请输入0到2之间的数字!"<<endl;}
				}
			}
			break;
		case 5:
			cout<<"该链表共有"<<pl.GetCount()<<"个节点"<<endl;
			break;
		case 6:
			quit=true;
			break;
		default:		break;
		}
		if(quit)
		{
			cout<<"程序结束"<<endl;
			break;
		}
	}	
}
#endif


int main()
{
	Repair A;
	A.Run();
	return 0;
}




运行结果:

1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出
1
0)返回 1)图书 2)药品:1
请输入编号:5
请输入图书价格:1.3
构造date...
构造book...
0)返回 1)图书 2)药品:2
请输入编号:2
请输入药品价格:10.2
构造date...
构造drug...
0)返回 1)图书 2)药品:2
请输入编号:2
请输入药品价格:12.3
构造date...
构造drug...
您输入的编号2与链表中第0个节点的编号重复
0)返回 1)图书 2)药品:3
0)返回 1)图书 2)药品:2
请输入编号:3
请输入药品价格:12.3
构造date...
构造drug...
0)返回 1)图书 2)药品:0
1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出
2
药品的编号:2
药品的价格:10.2
药品的编号:3
药品的价格:12.3
图书的编号:5
图书的价格:1.3
请按回车键返回主界面


1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出
4
0)返回 1)按编号查询 2)按序号查询:1
请输入要查询的编号:3
药品的编号:3
药品的价格:12.3
0)返回 1)按编号查询 2)按序号查询:2
请输入要查找的序号(链表的节点脚标号):3
找不到该序号的商品
0)返回 1)按编号查询 2)按序号查询:2
请输入要查找的序号(链表的节点脚标号):2
图书的编号:5
图书的价格:1.3
0)返回 1)按编号查询 2)按序号查询:0
1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出
2
药品的编号:2
药品的价格:10.2
药品的编号:3
药品的价格:12.3
图书的编号:5
图书的价格:1.3
请按回车键返回主界面
5
1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出
5
该链表共有3个节点
1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出
3
请输入您要删除的商品编号:
5
删除成功


1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出
2
药品的编号:2
药品的价格:10.2
药品的编号:3
药品的价格:12.3
请按回车键返回主界面


1)增加商品 2)列出所有商品 3)删除商品 4)查找商品 5)商品数目 6)退出
6
程序结束
删除第1个节点
删除第2个节点
Press any key to continue


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值