- 题目分析
建立一个手机通讯录系统。手机通讯录中的联系人的信息既可以存储在手机中,也可以存储在手机卡中,也可以同时存储在两个位置上。存储在手机卡的联系人的信息只包含用户名和电话号码两项信息。存储在手机上的联系人的信息包括姓名、电话号码,QQ号码、籍贯。根据题目要求实现功能。
手机卡联系人文件和手机联系人文件事先已经写好,名字分别是PhoneCard和Phone,格式为文本文件。
我做的通讯录管理系统一共包括七个类。
前两个类是信息类,分别是手机卡上联系人和手机联系人的信息,第二个类继承第三个类。
第三个类是一个虚基类,包含增、删、查、改、浏览的虚函数。
第四个类继承第三个虚基类,是手机卡上联系人的操作类。数据成员是第一个类的动态对象数组,一个映照容器将联系人名字和该联系人在动态数组的位置联系起来。成员函数包括增、删、查、改、浏览,动态数组相对普通的对象数组操作简单,可直接调用STL的vector类中的函数,映照容器的应用使查找元素进行操作变得相对简单。这个类中的构造函数和析构函数包括了文件的读出和写入。这个类中的Delete函数,实际上并未从对象数组中真正删除,只是设立了一个bool型数组vis[1001],将要删除元素数组的vis值设立为true(已访问)在写入文件时只写入vis值为false的数组,以此实现删除。
第五个类与第四个类操作完全类似,是对手机联系人的操作类。
第六个类是一个用户类,在这个类中第三个类得到利用,实现了多态。数据成员是第四个类和第五个类的对象。在类中进行选择操作,确定对手机卡联系人进行操作还是对手机联系人进行操作。除了前两个类的增、删、查、改、浏览操作,这里还包括了从手机卡和手机联系人的双向移动和双向复制操作函数。
第七个类是菜单类,显示用户界面进行操作。
二、实现代码
//PhoneCard.h
//在codeblocks建立的工程include文件夹下的PhoneCard.h
//第一个类的头文件
#ifndef PHONECARD_H
#define PHONECARD_H
#include
#include
using namespace std;
class PhoneCard
{
protected:
string Name;
string PhoneNumber;
public:
void setName(string name);
void setPhoneNumber(string phonenumber);
string getName();
string getPhoneNumber();
PhoneCard();
PhoneCard(string name,string phonenumber);
friend istream&operator>>(istream&input,PhoneCard&phoneC);
friend ostream&operator<<(ostream&output,PhoneCard&phoneC);
};
#endif // PHONECARD_H
//Phone.cpp
//工程中src文件夹下的P hone.cpp文件
//第一个类的cpp文件
#include "PhoneCard.h"
void PhoneCard::setName(string name){Name=name;}
void PhoneCard::setPhoneNumber(string phonenumber){PhoneNumber=phonenumber;}
string PhoneCard::getName(){return Name;}
string PhoneCard::getPhoneNumber(){return PhoneNumber;}
PhoneCard::PhoneCard(){}
PhoneCard::PhoneCard(string name,string phonenumber):
Name(name),PhoneNumber(phonenumber){}
istream&operator>>(istream&input,PhoneCard&phoneC)
{
input>>phoneC.Name>>phoneC.PhoneNumber;
return input;
}
ostream&operator<<(ostream&output,PhoneCard&phoneC)
{
output<
#include
#include"PhoneCard.h"
using namespace std;
class Phone : public PhoneCard
{
private:
string QQnumber;
string Address;
public:
void setQQnumber(string qq);
void setAddress(string address);
string getQQnumber();
string getAddress();
Phone();
Phone(string name,string phonenumber,string qq,string address);
friend istream&operator>>(istream&input,Phone&p);
friend ostream&operator<<(ostream&output,Phone&p);
};
#endif
// PHONE_H
//Phone.cpp
//src文件夹的Phone.cpp
//第二个类的cpp文件
#include "Phone.h"
void Phone::setQQnumber(string qq){QQnumber=qq;}
void Phone::setAddress(string address){Address=address;}
string Phone::getQQnumber(){return QQnumber;}
string Phone::getAddress(){return Address;}
Phone::Phone(){}
Phone::Phone(string name,string phonenumber,string qq,string address):
PhoneCard(name,phonenumber),QQnumber(qq),Address(address){}
istream&operator>>(istream&input,Phone&p)
{
input>>p.Name>>p.PhoneNumber>>p.QQnumber>>p.Address;
return input;
}
ostream&operator<<(ostream&output,Phone&p)
{
output<
#include"PhoneCard.h"
#include
#include
#include
#include
三、总结
大一时写的C++课程设计,当时写了两天左右,还是很锻炼人的。
在课程设计周之前的周末,我就大概看了一下题,构建了一下具体思路。在没有看后面老师写的思路之前,我想的是建立两个信息类,一个总的操作类(未实现,操作太繁),终端菜单类,至于多态的要求,我想了好久也没想到咋实现。然后看了题后的实现过程分析,把我想的总操作类分为了四个类,思路清晰,自然而然地也实现了多态。个人感觉实现系统最难的就是实现过程分析,分析具体过程已知,这个程序的难度已经降了一半。
之前朋友写的选课系统,用到了vector和map。想到我自从学了STL,好像已经很久没用里面的模板了。除了sort排序和vector偶尔用到,map和queue等等已经快忘记它们是什么了。我参考她的multimap用法,回顾了一下这部分知识。vector在添加删除元素很有优势,而且节省内存空间。multimap设置迭代器后查找元素十分快捷方便。所以我想在课程设计中用上vector和map。
思路和应用方法已经确定,我在周一时开始写程序。周一上午时写到第四个类和第五个类时,类的成员函数具体应用map和vector时还是卡住了一段时间,把map和vector具体应用多看了几遍,便会用了。主要是不想用for循环遍历,太麻烦,尤其是删元素时,太麻烦,很容易出错。STL这个省时省力的模板不用白不用。
周一下午大概是敲完了程序,编译过了,具体运行有问题。在顺思路时,发现我神奇地略过了第三个类,好像并没有用过它,说好的多态貌似没有。所幸加上个子类对象赋给父类指针并没有很麻烦。晚上时挨个功能运行了一下,调了几个小的错误。增删查改浏览操作没问题,在控制台上输出没问题,数据但读不到文件中去。
周二上午改了一上午文件写入操作,反复看了几遍,就是找不出错来,耐心耗尽,几乎崩溃。也把程序略读了几遍,顺便还挑出了几个cout输出提示的单词拼写错误,然而文件依然读不出来。中午回去找人帮忙看了一下,事实证明我看了那么多遍的读文件部分程序的确没错,之前的出了点小问题,比如判断==写成了赋值=,小错误不断。在别人帮助下,总算是调好了程序。实在不容易,心累。
后来帮忙调了几个程序,发现大部分是操作类时出错。自己写程序和帮别人调程序的感觉真不一样,调比写要累得多。帮忙解决了几个问题,但是读文件的错误没有调出来,感觉跟我写的差不多,就是弄不出来,对象数组中有新建立的对象,程序和文件的连接也没问题。但不能写在文件中。猜测可能是运算符运用有问题。
这次课程设计收获还是很大的,极大地锻炼了耐心。类的具体应用能力也得到了很大的提高,获益匪浅。