通讯录管理程序(面向对象 c++)

文章通过一系列实验介绍了通讯录管理系统的设计与实现,从基本的面向过程编程到面向对象设计,深入探讨了构造函数、多态、继承、操作符重载等OOP特性,以及静态成员、文件操作等高级主题,展示了如何逐步构建一个具备多态性和文件交互能力的通讯录系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实验之间的关系

程序以…为基础所练习知识点及功能
1.实验一CommEntryProcedural练习面向过程(结构体)编程–一条通讯录条目的管理
2.实验二CommEntry1练习面向对象(类)编程–一条通讯录条目的管理
3.实验三CommEntryConDestructor2练习类的构造与析构函数–一条通讯录条目的管理
4.实验四 CommsNPolymorphism2练习组合/聚集(UML)、构造与析构–非多态–通讯录管理程序
5.实验五 CommEntryInheritance2练习类的继承–朋友条目
6.实验六 CommsOverloadingOper2,3,4运用操作符重载–友元函数
7.实验七 CommEntryStatic2运用static数据成员
8.实验八CommsPolymorphism2,3,5练习多态–通讯录(一般条目,朋友条目)
9.实验九CommsNPolymorphismFile2,4练习文件的读写–非多态文件版通迅录

二、实验内容

1.实验一-通讯录条目非oop版

问题:通讯录管理程序。通讯录是由通讯录条目组成的。…
实验一要求:使用过程式编程编写一条通讯录条目管理程序。
测试程序:
1.输入通讯录条目
2.输出通讯录条目
3.修改姓名
4.修改电话
0.退出
完善通讯录条目程序:
1.加入对”地址”的管理
2.可以输入、输出条目。
3.可以修改条目的每一个子项(name, tel, addr)
参考代码:

/*-----通讯录条目非oop版----*/
#include <bits/stdc++.h>
using namespace std;
struct CommEntry{
    string mName;//结构体默认成员权限公开
    string mTel;
    string mAddr;//加入对”地址”的管理
};
int DisplayMenu(){
    string ch;
    while(true){
        cout << "-----通讯录条目非oop版----\n";
        cout << "--------------------------\n";
        cout << "1.输入通讯录条目\n";
        cout << "2.输出通讯录条目\n";
        cout << "3.修改姓名\n";
        cout << "4.修改电话\n";
        cout << "5.修改地址\n";
        cout << "0.退出\n";
        cout << "--------------------------\n";
        cout << "请输入您的选择(0-5):\n";
        while (getline(cin,ch)) if (ch.length()) break; // 获取用户输入,getline取字符串(包含空格)结束符不放入缓冲区
        if ('0' <= ch[0]&&ch[0] < '6' && ch.length() == 1) return int(ch[0]-'0');//判断输入是否合法,合法返回int 型数据
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
void InputCommEntry (CommEntry &ce){
    cout << "输入姓名为:" << endl;
    cin >> ce.mName;
    cout << "输入电话为:" << endl;
    cin >> ce.mTel;
    cout << "输入地址为:" << endl;
    cin >> ce.mAddr;
}
void OutputCommEntry (CommEntry &ce){
    cout << "姓名: " << ce.mName << endl;
    cout << "电话: " << ce.mTel << endl;
    cout << "地址: " << ce.mAddr <<endl;
}
void SetName(CommEntry &ce, string nm){//可更改每一个子项
    ce.mName = nm;
}
void SetTel(CommEntry &ce, string tel){
    ce.mTel = tel;
}
void SetAddr(CommEntry &ce, string addr){
    ce.mAddr = addr;
}
int  main(){
    CommEntry ceZS;
    int iChoice = 1;
    while (iChoice != 0){
        iChoice = DisplayMenu();
        switch (iChoice){
        case 1:
            InputCommEntry(ceZS);
            break;
        case 2:
            OutputCommEntry(ceZS);
            break;
        case 3:{
            string nm;
            cout << "修改姓名为:" << endl;
            cin >> nm;
            SetName(ceZS, nm);
            break;
        }
        case 4:{
            string tel;
            cout << "修改电话为:" << endl;
            cin >> tel;
            SetTel(ceZS, tel);
            break;
        }
        case 5:{
            string addr;
            cout << "修改地址为:" << endl;
            cin >> addr;
            SetAddr(ceZS, addr);
            break;
        }
        case 0:{
             cout<<"欢迎再次使用!";
            return 0;
        }
        }
        system("pause");
        system("cls");
    }
    return 0;
}

2.实验二-通讯录条目oop版

问题描述:通讯录条目由姓名、电话组成的。可以进行输入、输出、修改姓名、修改电话。(可以进行适当的扩展)

程序主菜单如下:
1.输入通讯录条目
2.输出通讯录条目
3.修改姓名
4.修改电话
0.退出

UML:

CommEntry
-name : string
-tel : string
+input() : void
+output() : void
+setName(string nm) : void
+setTel(string t) : void
+getName() : string
+getTel() : string

参考代码:

#include <bits/stdc++.h>
using namespace std;
class CommEntry{
public://默认成员函数为私有
    void InputCommEntry();
    void OutputCommEntry() const;//常函数,只读不写
    string GetName() const;
    string GetTel() const;
    void SetName(string nm);
    void SetTel(string tel);
private:
    string mName; //小驼峰命名方式
    string mTel;
};
int DisplayMenu(){
    string ch;
    while (true){
        cout << "------通讯录条目oop版-----\n";
        cout << "--------------------------\n";
        cout << "1.输入通讯录条目\n";
        cout << "2.输出通讯录条目\n";
        cout << "3.修改姓名\n";
        cout << "4.修改电话\n";
        cout << "0.退出\n";
        cout << "--------------------------\n";
        cout << "请输入您的选择(0-4):\n";
        while (getline(cin,ch)) if (ch.length()) break;//获取用户输入,getline取字符串(包含空格),while清除缓冲区回车同时检查是否只有回车时输入
        if ('0' <= ch[0]&&ch[0] < '5' && ch.length() == 1) return int(ch[0]-'0');//判断字符串是否合法,合法强制类型转换int 型数据返回
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
void CommEntry::InputCommEntry(){
    cout << "输入姓名为:" << endl;
    cin >> mName;
    cout << "输入电话为:" << endl;
    cin >> mTel;
}
void CommEntry::OutputCommEntry () const{
    cout << "姓名: " << GetName() << endl;//调用常函数,获取姓名和电话
    cout << "电话: " << GetTel() << endl;
}
string CommEntry::GetName() const{
    return mName;
}
string CommEntry::GetTel()  const{
    return mTel;
}
void CommEntry::SetName(string nm){
    mName = nm;
}
void CommEntry::SetTel(string tel){
    mTel = tel;
}
int  main(){
    CommEntry ceZS;
    int iChoice = 1;
    while (iChoice != 0){
        iChoice = DisplayMenu();
        switch (iChoice){
        case 1:
            ceZS.InputCommEntry();
            break;
        case 2:
            ceZS.OutputCommEntry();
            break;
        case 3:{
            string nm;
            cout << "修改姓名为:" << endl;
            cin >> nm;
            ceZS.SetName(nm);
            break;
        }
        case 4:{
            string tel;
            cout << "修改电话为:" << endl;
            cin >> tel;
            ceZS.SetTel(tel);
            break;
        }
        case 0:{
            cout<<"欢迎再次使用!";
            return 0;
        }
        }
        system("pause");
        system("cls");
    }
    return 0;
}

3.实验三-构造函数与析构函数

问题描述:通讯录条目由姓名、多个电话(各种类型的电话)组成的。可以进行输入、输出、修改姓名、修改电话。
分析:
(1)多个电话及其类型可用字符串动态数组存储。
int telCount;
string *tels;
string *telType;
(2)用构造函数完成多个电话的初始化。
tels = new string[num];
telType = new string[num];
(3)在析构函数中完成内存的回收。
delete []tels;
delete []telType;
(4)其它相应的函数也要做修改。
UML:

CommEntry
-name : string
-telCount : int
-tels : string []
-teletype : string []
+CommEntry(int num = 3)
+~CommEntry()
+input() : void
+output() : void
+setName(string nm) : void
+setTel(string t, int iNum) : void
+getName() : string
+getTel(int iNum) : string

参考代码:

#include <bits/stdc++.h>
using namespace std;
class CommEntry{
public:
    CommEntry(int num = 3); //构造函数设置缺省参数为3条
    int DisplayMenu(); //菜单展示
    void InputCommEntry();
    void OutputCommEntry() const ; //常函数,只读不写
    void SetName(string nm);
    void SetTel(string tel,int iNum);
    string GetName() const;
    string GetTel(int iNum)  const;
    void  DisplayTeltype() const;
    bool IfEmpty();//判断是否有记录
    ~CommEntry();
private:
    string mName;
    int mtelCount; //记录电话条数
    string *mTel;//多个电话(各种类型的电话)
    string *mtelType;
    bool mEmpty; //判断通讯录是否为空
};
CommEntry::CommEntry(int num){
    cout << "请输该联系人的电话个数:" << endl;
    cin >> mtelCount ;
    mEmpty = true; // 通讯录设置为空
    mTel = new string[mtelCount];  //堆区动态开辟空间,需要自动回收
    mtelType = new string[mtelCount ];  //指针指向新开辟数组开头
    cout << "设置成功!" << endl;
    system("pause");
    system("cls");
}
int CommEntry::DisplayMenu(){
    string ch;
    while(true){
        cout << "----构造函数与析构函数----\n";
        cout << "--------------------------\n";
        cout << "1.输入通讯录条目\n";
        cout << "2.输出通讯录条目\n";
        cout << "3.修改姓名\n";
        cout << "4.修改电话\n";
        cout << "0.退出\n";
        cout << "--------------------------\n";
        cout << "请输入您的选择(0-4):\n";
        while (getline(cin,ch)) if (ch.length()) break;//获取用户输入,getline取字符串(包含空格),while清除缓冲区回车同时检查是否只有回车时输入
        if ('0' <= ch[0]&&ch[0] < '5' && ch.length() == 1) return int(ch[0]-'0');//判断字符串是否合法,合法强制类型转换int 型数据返回
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
void CommEntry::InputCommEntry(){
    cout << "请输入姓名为:" << endl;
    cin >> mName;
    int i,j;
    for ( i = 0; i < mtelCount; i++){//检查类型重复
        cout << "请输入第" << i+1 << "个电话类型为:" << endl;
        while (cin >> mtelType[i]){
            for ( j = 0; j < i; j++)
                if (mtelType[i] == mtelType[j]) break; //检测是否与之前类型重复
            if (j < i ) cout << "该电话类型已经存在! 请重新输入。" << endl;
            else break;
        }
        cout << "请输入第" << i+1 << "个电话为:" << endl;
        cin >> mTel[i];
    }
    cout << " 输入成功 ! " << endl;
    mEmpty = false; // 通讯录设置为存在
}
void CommEntry::OutputCommEntry () const{
    cout << "\n------输出通讯录条目------\n";
    cout << "姓名: " << GetName() << endl;
    for(int i=0; i<mtelCount; i++){
        cout << i+1 << "." << mtelType[i]
             << "电话:"<< GetTel(i) << endl;
    }
     cout << "--------------------------\n";
}
void CommEntry::SetName(string nm){
    mName = nm;
}
void CommEntry::SetTel(string tel,int iNum){
    if( 0 <= iNum && iNum < mtelCount){
        mTel[iNum] = tel;
        cout << "修改成功!" << endl;
    }
    else cout << "输入无效,修改失败!" << endl;
}
string CommEntry::GetName() const{
    return mName;
}
string CommEntry::GetTel(int iNum) const{
    return mTel[iNum];
}
void CommEntry::DisplayTeltype() const{
    for (int i = 0; i < mtelCount; i++){
        cout << i+1 << "." << mtelType[i] << "\n";
    }
    cout << endl;
}
bool CommEntry::IfEmpty(){
    return mEmpty;
}
CommEntry::~CommEntry(){//在析构函数中完成内存的回收
    delete []mTel;// 堆区开辟空间程序结束时调用析构函数
    delete []mtelType;
}
int  main(){
    CommEntry ceZS;
    int iChoice = 1;
    while (iChoice != 0){
        iChoice = ceZS.DisplayMenu();
        switch (iChoice){
        case 1:
            if ( ceZS.IfEmpty())  ceZS.InputCommEntry();
            else cout << "通讯录已存在!" << endl;
            break;
        case 2:
            if ( !ceZS.IfEmpty()) ceZS.OutputCommEntry();
            else cout << "当前通讯录为空!"  << endl;
            break;
        case 3:
            if ( !ceZS.IfEmpty()){
                string nm;
                cout << "修改姓名为:" << endl;
                cin >> nm;
                ceZS.SetName(nm);
            }
            else cout << "当前通讯录为空!"  << endl;
            break;
        case 4:
            if ( !ceZS.IfEmpty()){
                cout << "请选择要修改的电话类型:" << endl;
                ceZS.DisplayTeltype();
                int iNum;
                cin >> iNum;
                cout << "请输入要修改的电话为:" << endl;
                string tel;
                cin >> tel;
                ceZS.SetTel(tel,iNum-1);
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 0:
            cout << "欢迎再次使用!";
            return 0;
        }
        system("pause");
        system("cls");
    }
    return 0;
}

4.实验四-非多态版的通讯录

通讯录管理程序

问题描述:通讯录管理程序。通讯录是由通讯录条目(不包括朋友条目,以后再考虑在通讯录中加入朋友类条目)组成的。通讯录总条目数。通讯录中现有多少条。可以输入通讯录、可以输出通讯录、可以查找、修改。
实验目标:学习使用类与类之间的组合关系。
与前面实验的关系:以第一个实验,通讯录条目程序为基础。
要点分析
(1)在原来通讯录条目的基础之上添加一个类Comms,CommEntry是Comms的数据成员。Comms的声明与定义可以使用单独的.h和.cpp文件。

(2)通迅录中有多个条目,所以CommEntry是以数组的形式出现在Comms中,为了能灵活处理通讯录条目的个数,可以指针的方式进行声明,然后动态的申请通讯录条目的个数,比如可以考虑在Comms的构造函数中进行内存的申请,在其析构函数中进行内存的回收。

(3)在Comms中定义两个整数:MaxCount, count,分别用了表示通讯录中条目的最多个数与已经存在的个数。

(4)在Comms中声明如下函数:
void inputAll():用于输入通迅录中的通讯录条目。注意在此函数中如何使用条目类的input()函数。
void outputAll():用于输出通讯录条目中的通讯录条目。注意在此函数中如何使用条目类的input()函数。
int find(string nm):用于在通讯录中按姓名查找一个通讯录条目在通讯录条目在通讯录中的位置,其返回值是找到的条目在数组中一下标位置。此函数主体可以用for循环来完成。供参考代码:

int Comms::find(string nm){
   int i;
   i = 0; 
   for (i=0;i<count;i++){
      if ((pCe[i]).getName()==nm){
         break;                         
      }
   }
   return i; 
}

void modify(stirng nm, string t):给定一个姓名,一个电话,修在改通讯录中此姓名对应的条目的电话为指定的电话。注意此函数与find函数的关系。
(5)Comms,CommEntry之间的关系是组合与被组合的关系,可以用以下UML图来表示:

Comms
-pCe : CommEntry *
-maxCount : int //管理的最多通迅录条目个数
-count : int
+inputAll() : void
+outputAll() : void
+find(string nm) : int
+modify(string nm, string t) : void
CommEntry
-name : string
-tel : string
+input()
+output()
+setName(string nm) : void
+setTel(string t) : void
+getName() : string
+getTel() : string

(6)程序主菜单如下。主控程序的结构与通讯录条目程序的结构类似。
1.输入通讯录
2.输出通讯录
3.查找姓名
4.修改(输入姓名,修改其电话)
0.退出
拓展:
1、根据给定的电话查找姓名。
2、模糊查找。
参考代码:
main.cpp

#include"CommEntry.h"
#include"Comms.h"
int  main(){
    Comms ceZS(5);
    int iChoice = 1;
    while (iChoice != 0){
        iChoice = ceZS.Menu();
        switch (iChoice){
        case 1:
            if ( ceZS.IfEmpty()) ceZS.InputAll();
            else cout << "通讯录已存在!" << endl;
            break;
        case 2:
            if ( !ceZS.IfEmpty()) ceZS.OutputAll();
            else cout << "当前通讯录为空!" << endl;
            break;
        case 3:
            if ( !ceZS.IfEmpty()){
                cout << "请输入要查找的姓名 :" << endl;
                string nm;
                cin >> nm;
                int num = ceZS.Find(nm);
                if (num != -1)
                    cout<< "该姓名为通讯录中第" << num+1 << "条"<<endl;
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 4:
            if ( !ceZS.IfEmpty()){
                string nm, tel;
                cout << "请输入要修改的姓名:" << endl;
                cin >> nm;
                cout << "请输入要设置的指定电话为:" << endl;
                cin >> tel;
                ceZS.Modify(nm,tel);
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 5:
            if ( !ceZS.IfEmpty()){
                cout << "请输入要查找用户的电话:" << endl;
                string tel;
                cin >> tel;
                ceZS.FindName(tel);
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 6:
            if ( !ceZS.IfEmpty()){
                cout << "请输入要查找的电话或姓名:" << endl;
                string str;
                cin >> str;
                ceZS.FuzzyMatch(str);
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 0:
            cout<<"欢迎再次使用!";
            return 0;
        }
        system("pause");
        system("cls");
    }
    return 0;
}

Comms.h

#pragma once
#include<bits/stdc++.h>
#include"CommEntry.h"
using namespace std;
#define llu long long unsigned
class Comms {//使用类与类之间的组合关系
public:
    Comms(int up=10);
    ~Comms();
    int Menu();
    void InputAll();
    void OutputAll();
    int Find(string nm);
    void Modify(string nm, string t);
    void FindName( string tel);
    void FuzzyMatch(string str);
    bool IfEmpty();
private:
    CommEntry * mpCe ; //通讯录由通讯录条目组成
    int mmaxCount;
    int mcount;
    bool mEmpty;
};


Comms.cpp

#include"Comms.h"
int Comms::Menu(){
    string ch;
    while(true){
        cout << "---------非多态版通讯录---------\n";
        cout << "--------------------------------\n";
        cout << "1.输入通讯录\n";
        cout << "2.输出通讯录\n";
        cout << "3.查找姓名(输出在通讯录中的位置)\n";
        cout << "4.修改(输入姓名,设置指定电话)\n";
        cout << "5.根据电话查找姓名\n";
        cout << "6.模糊查找\n";
        cout << "0.退出\n";
        cout << "--------------------------------\n";
        cout << "请输入您的选择(0-6):\n";
        while (getline(cin,ch)) if (ch.length()) break;
        if ('0' <= ch[0]&&ch[0] < '7' && ch.length() == 1) return int(ch[0]-'0');
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
Comms::Comms(int up){
    mmaxCount = up;
    mpCe = new CommEntry[mmaxCount];  //堆区开辟数组
    mcount = 0;
    mEmpty = true; // 通讯录设置为空
}
void Comms:: InputAll(){
    int iCount;
    cout << "请输入要输入的通讯录的条目个数:";
    cin >> iCount;
    if (0 < iCount && iCount < mmaxCount) {// 判断是否合法
        mcount = iCount;
        for (int i = 0; i < mcount; i++){
            cout << "请输入第" << i+1 ;
            mpCe[i].InputCommEntry();
        }
        mEmpty = false; // 通讯录设置为存在
        cout << "输入成功! " << endl;
    }
    else cout << "输入无效! " << endl;
}
void Comms::OutputAll(){
    cout << "\n---------输出通讯录-------------\n";
    for (int i = 0; i < mcount; i++){
        cout << "第" << i+1 << "个联系人:  " << endl;
        mpCe[i].OutputCommEntry();
    }
}
int Comms::Find(string nm){
    for (int i = 0; i < mcount; i++){
        if (mpCe[i].GetName() == nm) return i;
    }
    cout << "该姓名不存在!"<< endl;
    return -1;
}
void Comms::Modify(string nm, string t){
    int num = Find(nm);
    if(num != -1){
        mpCe[num].SetTel(t);
        cout << " 指定电话设置成功! " << endl;
    }
}
void Comms::FindName( string tel){
    int i;
    for ( i = 0; i < mcount; i++){
        if (mpCe[i].FindTel(tel)){
            cout << "该联系人姓名为 :" << mpCe[i].GetName() << endl;
            break;
        }
    }
    if (i == mcount) cout << "该姓名不存在! " << endl;
}
void Comms::FuzzyMatch(string str) {//模糊查找
    bool flag = false;
    for(int i = 0; i < mcount; i++){
        if (mpCe[i].GetName().find(str) != (llu)-1){
            flag = true;
            mpCe[i].OutputCommEntry();//如果找到该字符串为姓名子串,输出该联系人所有信息
        }
        else{
            bool f = false;
            for(int j = 0; j < mpCe[i].GetTelcount(); j++){
                if ( mpCe[i].GetTel(j).find(str) != (llu) -1){//如果找到该字符串为电话子串,输出该联系人电话和姓名
                    cout << mpCe[i].GetTel(j) << endl;
                    f = true;
                    flag = true;
                }
            }
            if (f) cout << mpCe[i].GetName() << endl;
        }
    }
    if(!flag) cout << "未匹配到!" << endl;
}
bool Comms::IfEmpty(){
    return mEmpty;
}
Comms::~Comms(){
    delete []mpCe;//内存回收先调用 CommEntry(数据成员)的析构函数
}

CommEntry.h

#pragma once
#include<bits/stdc++.h>
using namespace std;
class CommEntry{
public:
    CommEntry(int num = 20); // 设置缺省构造函数
    void InputCommEntry();
    void OutputCommEntry() const;
    void SetTel(string tel);
    string GetName() const ;
    string GetTel(int iNum) const ;
    int GetTelcount() const;
    bool FindTel(string tel);
    ~CommEntry();
private:
    string mName;
    int mtelCount;
    int mmaxCount;
    string *mTel;;
    string *mtelType;
};

CommEntry.cpp

#include"CommEntry.h"
CommEntry::CommEntry(int up){
    mmaxCount = up;
    mTel = new string[mmaxCount];  // 堆区动态开辟空间,需要自动回收
    mtelType = new string[mmaxCount];  //指针指向新开辟数组开头
}
void CommEntry::InputCommEntry(){
    cout << "个联系人的电话个数:";
    cin >> mtelCount ;
    cout << "请输入姓名为:" << endl;
    cin >> mName;
    int i,j;
    for ( i = 0; i < mtelCount; i++){
        cout << "请输入第" << i+1 << "个电话类型为:" << endl;
        while (cin >> mtelType[i]){
            for ( j = 0; j < i; j++)
                if (mtelType[i] == mtelType[j]) break;
            if (j < i) cout << "该电话类型已经存在! 请重新输入。" << endl;
            else break;
        }
        cout << "请输入第" << i+1 << "个电话为:" << endl;
        cin >> mTel[i];
    }
}
void CommEntry::OutputCommEntry () const{
    cout << "姓名: " << GetName() << "\n";
    for(int i=0; i<mtelCount; i++){
        cout << i+1 << "." << mtelType[i]
             << "电话:"<< GetTel(i) << "\n";
    }
    if ( mtelType[mtelCount] == "指定电话:  ")
        cout << mtelType[mtelCount] << mTel[mtelCount] << endl;
    cout << "--------------------------------\n";
}
string CommEntry::GetName() const{
    return mName;
}
string CommEntry::GetTel(int iNum) const{
    return mTel[iNum];
}
void CommEntry::SetTel(string tel){
    mTel[mtelCount] = tel;
    mtelType[mtelCount] = "指定电话:  ";
}
int CommEntry::GetTelcount() const{
    return mtelCount;
}
bool CommEntry::FindTel(string tel){
    for(int j = 0; j <= mtelCount; j++){
        if(tel == this->mTel[j]) return true;
    }
    return false;
}
CommEntry::~CommEntry(){
    delete []mTel;
    delete []mtelType; //delete 执行之前调用该析构函数
}

5.实验五-继承ForStu

本次实验要求:
一、朋友条目:具备一般条目的特点,此外还有地址属性
根据描述有如下UML图。FreindEntry是CommEntry的子类。

CommEntry
#name : string
#tel : string
+input() : void
+output() : void
+setName(string nm) : void
+setTel(string t) : void
+getName() : string
+getTel() : string
FriendEntry
-addr:string
+input() : void
+output() : void
+setAddr(string a) : void
+getAddr() : string

要求编写一个程序,可以管理朋友条目。所用的知识点是“继承”
程序的主菜单如下:
1.输入朋友条目
2.输出朋友条目
3.修改姓名
4.修改电话
5.修改地址
0.退出

分析:
(1) 编写一个新类FreindEntry,此类是CommEntry的子类。
(2) FreindEntry有数据成员addr,用于存放一个朋友条目的地址。
(3) 根据分析,需要新编写四个函数。
void input() ; //提示:如何使用父类的同名函数
void output(); //提示:如何使用父类的同名函数
void setAddr(string a)
string getAddr():
参考代码:
main.cpp

#include"CommEntry.h"
#include"FreindEntry.h"
#include"Student.h"
int  main()
{
    cout << "请选择使用 (1.朋友条目  2.同学条目):";
    int cho;
    cin >> cho;
    if (cho == 1){
        FreindEntry ceZS; //创建朋友实例
        int iChoice = 1;
        while (iChoice != 0){
            iChoice = ceZS.DisplayMenu();
            switch (iChoice){
            case 1:
                ceZS.InputCommEntry();//子类和父类同名时不加作用域默认访问子类的成员
                break;//调用父类成员 ceZS.CommEntry::InputCommEntry();
            case 2:
                ceZS.OutputCommEntry();
                break;
            case 3:{
                string nm;
                cout << "修改姓名为:" << endl;
                cin >> nm;
                ceZS.SetName(nm);
                break;
            }
            case 4:{
                string tel;
                cout << "修改电话为:" << endl;
                cin >> tel;
                ceZS.SetTel(tel);
                break;
            }
            case 5:{
                string a;
                cout << "修改地址为:" << endl;
                cin >> a;
                ceZS.SetAddr(a);
                break;
            }
            case 0:{
                cout<<"欢迎再次使用!";
                exit(0);
            }
            }
            system("pause");
            system("cls");
        }
    }
     else if(cho ==  2){
        Student ceZS;
        int iChoice = 1;
        while (iChoice != 0){
            iChoice = ceZS.DisplayMenu();
            switch (iChoice){
            case 1:
                ceZS.InputCommEntry();
                break;
            case 2:
                ceZS.OutputCommEntry();
                break;
            case 3:{
                string nm;
                cout << "修改姓名为:" << endl;
                cin >> nm;
                ceZS.SetName(nm);
                break;
            }
            case 4:{
                string tel;
                cout << "修改电话为:" << endl;
                cin >> tel;
                ceZS.SetTel(tel);
                break;
            }
            case 5:{
                string a;
                cout << "修改学校为:" << endl;
                cin >> a;
                ceZS.SetSchool(a);
                break;
            }
            case 6:{
                string a;
                cout << "修改班级为:" << endl;
                cin >> a;
                ceZS.SetClass(a);
                break;
            }
            case 0:{
                cout<<"欢迎再次使用!";
                exit(0);
            }
            }
            system("pause");
            system("cls");
        }
    }
    else cout << "输入不合法!";
    return 0;
}

CommEntry.h

#pragma once
#include<bits/stdc++.h>
using namespace std;
class CommEntry{
public:
    void InputCommEntry();
    void OutputCommEntry() const;
    string GetName() const;
    string GetTel() const;
    void SetName(string nm);
    void SetTel(string tel);
protected: // 公有继承下子类可以访问
    string mName; //下划线命名方式
    string mTel;
};

CommEntry.cpp

#include"CommEntry.h"
void CommEntry::InputCommEntry(){
    cout << "输入姓名为:" << endl;
    cin >> mName;
    cout << "输入电话为:" << endl;
    cin >> mTel;
}
void CommEntry::OutputCommEntry () const{
    cout << "姓名: " << GetName() << endl;//调用常函数,获取姓名和电话
    cout << "电话: " << GetTel() << endl;
}
string CommEntry::GetName() const{
    return mName;
}
string CommEntry::GetTel()  const{
    return mTel;
}
void CommEntry::SetName(string nm){
    mName = nm;
}
void CommEntry::SetTel(string tel){
    mTel= tel;
}

FreindEntry.h

#pragma once
#include<bits/stdc++.h>
#include"CommEntry.h"
using namespace std;
class FreindEntry: public CommEntry {// 公有继承关系
public:
    int DisplayMenu();
    void InputCommEntry();/*子类中的成员将隐藏父类中的同名成员
    父类中的同名成员依然存在于子类中,需要用作用域分辨符(::)访问父类同名成员*/
    void OutputCommEntry() const;
    void SetAddr(string a);
    string GetAddr( ) const;
private:
    string mAddr;
};

FreindEntry.cpp

#include"FreindEntry.h"
int FreindEntry::DisplayMenu(){
    string ch;
    while(true){
        cout << "---通讯录条目(继承)---\n";
        cout << "------------------------\n";
        cout << "1.输入通讯录条目\n";
        cout << "2.输出通讯录条目\n";
        cout << "3.修改姓名\n";
        cout << "4.修改电话\n";
        cout << "5.修改地址\n";
        cout << "0.退出\n";
        cout << "------------------------\n";
        cout << "请输入您的选择(0-5):\n";
        while (getline(cin,ch)) if (ch.length()) break;
        if ('0' <= ch[0]&&ch[0] < '6' && ch.length() == 1) return int(ch[0]-'0');
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
void FreindEntry::InputCommEntry(){
    cout << "输入姓名为:" << endl;
    cin >> mName;
    cout << "输入电话为:" << endl;
    cin >> mTel;
    cout << "输入地址为:" << endl;
    cin >> mAddr;
}
void FreindEntry::OutputCommEntry () const{
    cout << "姓名: " << GetName() << endl;
    cout << "电话: " << GetTel() << endl;
    cout << "地址: " << GetAddr() << endl;
}
void FreindEntry::SetAddr(string a){
    mAddr = a;
}
string FreindEntry::GetAddr()  const{
    return mAddr;
}

二、扩展练习
1.朋友条目还具有Email属性,试改造以上程序,使朋友条目还可以管理Email。

2.编写一下同学条目管理程序。同学条目:是条目的一种,除具备一般条目的信息外,还有学校,班级的信息。仿照朋友条目的分析与设计,编写一个管理同学条目的例子。主程序菜单如下:
1.输入同学条目
2.输出同学条目
3.修改姓名
4.修改电话
5.修改学校
6.修改班级
0.退出
参考代码:
Student.h

#pragma once
#include<bits/stdc++.h>
#include"CommEntry.h"
using namespace std;
class Student: public CommEntry{
public:
    int DisplayMenu();
    void InputCommEntry();
    void OutputCommEntry() const;
     void SetSchool(string sch);
    string GetSchool( ) const;
     void SetClass(string cls);
    string GetClass( ) const;
private:
    string mAddr;
    string mschool;
    string mclass;
};

Student.cpp

#include"Student.h"
int Student::DisplayMenu(){
    string ch;
    while(true){
        cout << "---通讯录条目(继承)---\n";
        cout << "------------------------\n";
        cout << "1.输入通讯录条目\n";
        cout << "2.输出通讯录条目\n";
        cout << "3.修改姓名\n";
        cout << "4.修改电话\n";
        cout << "5.修改学校\n";
        cout << "6.修改班级\n";
        cout << "0.退出\n";
        cout << "------------------------\n";
        cout << "请输入您的选择(0-6):\n";
        while (getline(cin,ch)) if (ch.length()) break;
        if ('0' <= ch[0]&&ch[0] < '7' && ch.length() == 1) return int(ch[0]-'0');
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
void Student::InputCommEntry(){
    cout << "输入姓名为:" << endl;
    cin >> mName;
    cout << "输入电话为:" << endl;
    cin >> mTel;
    cout << "输入学校为:" << endl;
    cin >> mschool;
    cout << "输入班级为:" << endl;
    cin >> mclass;
}
void Student::OutputCommEntry () const{
    cout << "姓名: " << GetName() << endl;
    cout << "电话: " << GetTel() << endl;
    cout << "学校: " << GetSchool() << endl;
    cout << "班级: " << GetClass() << endl;
}
void Student::SetSchool(string sch){
    mschool = sch;
}
string Student::GetSchool()  const{
    return mschool;
}
void Student::SetClass(string cls){
    mclass = cls;
}
string Student::GetClass()  const{
    return mclass;
}


6.实验六-操作符重载

实验要求:
重载运算符<<, >>.使得其可用于CommEntry.
技术要点:
(1)为了方便,用全局运算符重载。
(2)为能访问类中的私有成员,可定义为友元函数。在CommEntry的类声明文件中声明:
// 函数访问非public成员时,必为友元
friend ostream& operator<<(ostream&, CommEntry&);
friend istream& operator>>(istream&, CommEntry&);
(3)在CommEntry的类定义文件中定义全局函数:
//–operater overloading
istream& operator>>( istream& in, CommEntry& c ){
// …
}
ostream& operator<<( ostream& out, CommEntry& c ){
//…
}
(4)使用
CommEntry ce;
//… …
cin>>ce;
cout<<ce;
作业:重载运算符<<, >>.使得其可用于Comms。

参考代码:
main.cpp

#include"Comms.h"
int  main() {
    Comms ceZS;
    int iChoice = 1;
    while (iChoice != 0) {
        iChoice = ceZS.DisplayMenu();
        switch (iChoice){
        case 1:
            cin >> ceZS;
            break;
        case 2:
            cout << ceZS;
            break;
        case 3:{
            int num;
            cout << "请输入要修改第几个联系人的姓名:";
            cin >> num;
            string nm;
            cout << "修改姓名为:" << endl;
            cin >> nm;
            ceZS.SetName(--num,nm);
            break;
        }
        case 4:{
            int num;
            cout << "请输入要修改第几个联系人的电话:";
            cin >> num;
            string tel;
            cout << "修改电话为:" << endl;
            cin >> tel;
            ceZS.SetTel(--num,tel);
            break;
        }
        case 0:
            cout<<"欢迎再次使用!";
            return 0;
        }
        system("pause");
        system("cls");
    }
    return 0;
}

Comms.h

#pragma once
#include<bits/stdc++.h>
#include"CommEntry.h"
using namespace std;
class Comms { //使用类与类之间的组合关系
    friend ostream& operator<<(ostream&, Comms&);//友元函数有权访问类的私有成员
    friend istream& operator>>(istream&, Comms&);
public:
    Comms(int up=10);
    ~Comms();
    int DisplayMenu();
    void SetName(int num,string nm);
    void SetTel(int num,string tel);
private:
    CommEntry * mpCe ; //通讯录由通讯录条目组成
    int mmaxCount;
    int mcount;
};


Comms.cpp

#include"Comms.h"
int Comms::DisplayMenu(){
    string ch;
    while(true){
        cout << "----通讯录操作符重载----\n";
        cout << "------------------------\n";
        cout << "1.输入通讯录条目\n";
        cout << "2.输出通讯录条目\n";
        cout << "3.修改姓名\n";
        cout << "4.修改电话\n";
        cout << "0.退出\n";
        cout << "------------------------\n";
        cout << "请输入您的选择(0-4):\n";
        while (getline(cin,ch)) if (ch.length()) break;
        if ('0' <= ch[0]&&ch[0] < '5' && ch.length() == 1) return int(ch[0]-'0');
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
Comms::Comms(int up) { //初始化
    mmaxCount = up;
    mpCe = new CommEntry[mmaxCount];  //堆区开辟数组
    mcount = 0;
}
istream& operator>>(istream& in, Comms& C) { //全局运算符 >> 重载
    int iCount;
    cout << "请输入要输入的通讯录的条目个数:";
    cin >> iCount;
    if (0 < iCount && iCount < C.mmaxCount) { // 判断是否合法
        C.mcount = iCount;
        for (int i = 0; i < C.mcount; i++){
            printf("第%d个联系人电话:\n",i+1);
            cin >> C.mpCe[i];
        }
        cout << "输入成功! " << endl;
    }
    else cout << "输入无效! " << endl;
    return in;
}
ostream& operator<<(ostream& out, Comms& C)  { //全局运算符 << 重载
    cout << "-------输出通讯录-------\n";
    for (int i = 0; i < C.mcount; i++){
        cout << "第" << i+1 << "个联系人:  " << endl;
        cout << C.mpCe[i];
        cout << "------------------------\n";
    }
    return out;
}
void Comms::SetName(int num,string nm){
    if (0 <= num && num < mcount)
        mpCe[num].SetName(nm);
    else cout << "输入无效!\n";
}
void Comms::SetTel(int num,string tel){
    if (0 <= num && num < this->mcount)
        mpCe[num].SetTel(tel);
    else cout << "输入无效!\n";
}
Comms::~Comms(){
    delete []mpCe;//内存回收先调用 CommEntry的析构函数
}

CommEntry.h

#pragma once
#include<bits/stdc++.h>
using namespace std;
class CommEntry{
    friend ostream& operator<<(ostream&, CommEntry&);
    friend istream& operator>>(istream&, CommEntry&);
public:
    string GetName() const;
    string GetTel() const;
    void SetName(string nm);
    void SetTel(string tel);
private:
    string mName;
    string mTel;
};

CommEntry.cpp

#include"CommEntry.h"
ostream& operator<<(ostream& out, CommEntry& C) { //全局运算符 << 重载
    cout << "姓名: " << C.mName << endl;
    cout << "电话: " << C.mTel << endl;
    return out;
}
istream& operator>>(istream& in, CommEntry& C) { //全局运算符 >> 重载
    cout << "输入姓名为:" << endl;
    cin >> C.mName;
    cout << "输入电话为:" << endl;
    cin >> C.mTel;
    return in;
}
string CommEntry::GetName() const{
    return mName;
}
string CommEntry::GetTel()  const{
    return mTel;
}
void CommEntry::SetName(string nm){
    mName = nm;
}
void CommEntry::SetTel(string tel){
    mTel= tel;
}

7.实验七-静态数据成员

问题:通讯录管理程序。通讯录是由通讯录条目组成的。…
子问题:通讯录条目由姓名、电话组成的。可以进行输入、输出、修改姓名、修改电话。
实验要求:加入静态数据成员,拥有者Owner
UML :

CommEntry
-name : string
-tel : string
-Owner : static string
+input() : void
+output() : void
+setName(string nm) : void
+setTel(string t) : void
+getName() : string
+getTel() : string
+getOwner() : string
+setOwner(string ow) : void

测试程序:
1.输入通讯录条目
2.输出通讯录条目
3.修改姓名
4.修改电话
5.修改拥有者
0.退出

静态数据成员并不是针对某个类的实例对象,而是属于整个类的,为所有的对象实例所共有。他在作用域的范围内是全局的,独立于类的对象之外的。当实例化一个类的对象时候,里面不存在静态成员
在类中使用静态成员的目的是为了解决数据共享的的问题:如果想在同类中的多个对象之间实现数据共享,又避免使用全局变量,那么可以用类的静态数据成员来实现。
PS: 如果使用全局变量,这样很不安全,因为全局变量的值被所有函数所共享,可以在任何函数中被修改,而且在大项目中,它很容易与其他名字相冲突。因此在实际中很少使用全局变量。
在C++中类的数据成员如果被声明为static,那么它就是静态数据成员,意味着它为该类的所有对象共享。
参考代码:
main.cpp

#include"CommEntry.h"
int  main() {
    CommEntry ceZS; //创建朋友实例
    int iChoice = 1;
    while (iChoice != 0){
        iChoice = ceZS.DisplayMenu();
        switch (iChoice){
        case 1:
            ceZS.InputCommEntry();
            break;
        case 2:
            ceZS.OutputCommEntry();
            break;
        case 3:{
            string nm;
            cout << "修改姓名为:" << endl;
            cin >> nm;
            ceZS.SetName(nm);
            break;
        }
        case 4:{
            string tel;
            cout << "修改电话为:" << endl;
            cin >> tel;
            ceZS.SetTel(tel);
            break;
        }
        case 5:{
            string ow;
            cout << "修改拥有者为:" << endl;
            cin >> ow;
            ceZS.SetOwner(ow);
            break;
        }
        case 0:
            cout<<"欢迎再次使用!";
            return 0;
        }
        system("pause");
        system("cls");
    }
    return 0;
}

CommEntry.h

#pragma once
#include<bits/stdc++.h>
using namespace std;
class CommEntry{
public:
    int DisplayMenu();
    void InputCommEntry();
    void OutputCommEntry() const;
    string GetName() const;
    string GetTel() const;
    string GetOwner() const;
    void SetName(string nm);
    void SetTel(string tel);
    void SetOwner(string ow);
private:
    string mName;
    string mTel;
    static string mOwner;
};

CommEntry.cpp

#include"CommEntry.h"
string  CommEntry::mOwner = "张三";//在全局作用域对静态数据成员初始化,如果不赋予初值,则使用其默认值零
int CommEntry::DisplayMenu(){
    string ch;
    while(true){
        cout << "----静态数据成员----\n";
        cout << "--------------------\n";
        cout << "1.输入通讯录条目\n";
        cout << "2.输出通讯录条目\n";
        cout << "3.修改姓名\n";
        cout << "4.修改电话\n";
        cout << "5.修改拥有者\n";
        cout << "0.退出\n";
        cout << "--------------------\n";
        cout << "请输入您的选择(0-5):\n";
        while (getline(cin,ch)) if (ch.length()) break;
        if ('0' <= ch[0]&&ch[0] < '6' && ch.length() == 1) return int(ch[0]-'0');
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
void CommEntry::InputCommEntry(){
    cout << "输入姓名为:" << endl;
    cin >> mName;
    cout << "输入电话为:" << endl;
    cin >> mTel;
    cout << "输入拥有者为:" << endl;
    cin >> CommEntry::mOwner;
}
void CommEntry::OutputCommEntry () const{
    cout << "姓名: " << GetName() << endl;//调用常函数,获取姓名和电话
    cout << "电话: " << GetTel() << endl;
    cout << "拥有者: " << GetOwner() << endl;
}
string CommEntry::GetName() const{
    return mName;
}
string CommEntry::GetTel()  const{
    return mTel;
}
string CommEntry::GetOwner()  const{
    return mOwner;
}
void CommEntry::SetName(string nm){
    mName = nm;
}
void CommEntry::SetTel(string tel){
    mTel = tel;
}
void CommEntry::SetOwner(string ow){
    mOwner = ow;
}

8.实验八-多态版的通讯录

通讯录管理程序
问题描述:通讯录管理程序。通讯录是由通讯录条目组成的。通讯录总条目数。通讯录中现有多少条。可以输入通讯录、可以输出通讯录、可以查找、修改。

实验要求: 其中的通讯录条目可以是一般条目,也可以是朋友条目

UML:

Comms
CommEntry
FriendEntry

要求:
1.输入通讯录
2.输出通讯录
3.查找姓名
4.修改(输入姓名,修改其电话)
0.退出

技术要点:
指针数组:数组中的每一个元素是一个指针,可以指向一般条目的对象,也可以指向朋友条目的对象。

在这里插入图片描述
指针数组的声明: CommEntry ** pCes;
申请内存: pCes = new CommEntry * [maxCount];
回收内存:
for(int i=0; i<=count;i++){
delete pCes[i];
}
delete []pCes;
元素的使用:

 if (iType==1){
          pCes[i] = new CommEntry;           
       } else if(iType ==2){
          pCes[i] = new FriendEntry;           
       }
… …
   for (int i=0;i<count;i++){  //注意,下一行是多态函数的调用
      (pCes[i])->output();
   }

以下是实验要求:
1.输出通讯录时,根据据条目的实际类型(一般或是朋友)输出条目内容。提示:使用多态。
2.在输入通讯录时,根据据用户的要求创建通迅目的管理条目数。
3.(选做)写一个成员函数,分开显示朋友条目与一般条目。提示:使用RTTI技术。

参考代码:
main.cpp

#include"CommEntry.h"
#include"Comms.h"
int  main(){
    Comms ceZS;
    int iChoice = 1;
    while (iChoice != 0){
        iChoice = ceZS.DisplayMenu();
        switch (iChoice){
        case 1:
            if (ceZS.IfEmpty()) ceZS.InputAll();
            else cout << "通讯录已存在!" << endl;
            break;
        case 2:
            if ( !ceZS.IfEmpty()) ceZS.OutputAll();
            else cout << "当前通讯录为空!" << endl;
            break;
        case 3:
            if ( !ceZS.IfEmpty()){
                cout << "请输入要查找的姓名 :" << endl;
                string nm;
                cin >> nm;
                int num = ceZS.Find(nm);
                if (num != -1)
                    cout<< "该姓名为通讯录中第" << num+1 << "条"<<endl;
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 4:
            if (!ceZS.IfEmpty()){
                string nm, tel;
                cout << "请输入要修改的姓名:" << endl;
                cin >> nm;
                cout << "请输入要设置的指定电话为:" << endl;
                cin >> tel;
                ceZS.Modify(nm,tel);
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 5:
            if ( !ceZS.IfEmpty()) ceZS.CategoriesShow();
            else cout << "当前通讯录为空!" << endl;
            break;
        case 0:
            cout<<"欢迎再次使用!";
            return 0;
        }
        system("pause");
        system("cls");
    }
    return 0;
}

Comms.h

#pragma once//包含一次头文件
#include<bits/stdc++.h>
#include"CommEntry.h"
#include"FriendEntry.h"
using namespace std;
class Comms{
public:
     Comms(int up=6);
    ~Comms();
     int DisplayMenu();
     void InputAll();
    void OutputAll();
    int Find(string nm);
    void Modify(string nm, string t);
    void CategoriesShow();
    bool IfEmpty();
private:
    CommEntry **pCes;
    int mmaxCount;
    int mcount;
    bool mEmpty;
};

Comms.cpp

#include"Comms.h"
Comms::Comms(int up){
    mmaxCount = up;
    pCes = new CommEntry *[mmaxCount];//commentry指针类型数组
    mcount = 0;
    mEmpty = true; // 通讯录设置为空
}
int Comms::DisplayMenu(){
    string ch;
    while(true){
        cout << "---------多态版通讯录---------\n";
        cout << "------------------------------\n";
        cout << "1.输入通讯录条目\n";
        cout << "2.输出通讯录条目\n";
        cout << "3.查找姓名\n";
        cout << "4.修改(输入姓名,设置指定电话)\n";
        cout << "5.分开显示朋友条目与一般条目\n";
        cout << "0.退出\n";
        cout << "------------------------------\n";
        cout << "请输入您的选择(0-5):\n";
        while (getline(cin,ch)) if (ch.length()) break;
        if ('0' <= ch[0]&&ch[0] < '6' && ch.length() == 1) return int(ch[0]-'0');
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
void Comms:: InputAll(){
    int iCount;
    cout << "请输入要输入的通讯录的条目个数:";
    cin >> iCount;
    if (0 < iCount && iCount < mmaxCount) { // 判断是否合法
        mcount = iCount;
        for (int i = 0; i < mcount; i++){
            cout << "请输入第" << i+1 << "个联系人的类型序号:(1.一般条目  2.朋友条目)\n";
            int iType;
            while( cin >> iType){
                if ( 0 < iType &&  iType < 3) break;
                else   cout << "类型无效!请重新输入:" << endl;
            }
            if (iType==1){
                pCes[i] = new CommEntry;
            }
            else if (iType ==2){
                pCes[i] = new FriendEntry;
            }
            pCes[i]-> InputCommEntry();
            mEmpty = false; // 通讯录设置为存在
            cout << "输入成功! " << endl;
        }
    }
    else cout << "输入无效! " << endl;
}
void Comms::OutputAll(){
    cout << "---------输出通讯录-----------\n";
    for (int i = 0; i < mcount; i++)
    {
        cout << "第" << i+1 << "个联系人:  " << endl;
        pCes[i]->OutputCommEntry();//多态调用
    }
}
int Comms::Find(string nm){
    for (int i = 0; i < mcount; i++){
        if (pCes[i]->GetName() == nm) return i;
    }
    cout << "该姓名不存在!"<< endl;
    return -1;
}
void Comms::Modify(string nm, string t){
    int num = Find(nm);
    if(num != -1){
        pCes[num]->SetTel(t);
        cout << " 指定电话设置成功! " << endl;
    }
}
bool Comms::IfEmpty(){
    return mEmpty;
}
void Comms::CategoriesShow(){ //RTTI 技术
     bool flag = false;
    cout << "一般条目:" << endl;
    for(int i = 0 ; i < mcount; i++){
        if (typeid(CommEntry)==typeid(*pCes[i])){
            pCes[i]->OutputCommEntry();
            flag = true ;// 存在一般条目
        }
    }
    if( !flag) cout << "无" << endl;
    else flag = false;
    cout << "\n朋友条目:" << endl;
    for(int i = 0 ; i < mcount; i++){
        if (typeid(FriendEntry)==typeid(*pCes[i])){
            pCes[i]->OutputCommEntry();
             flag = true ;// 存在朋友条目
        }
    }
    if( !flag) cout << "无" << endl;
}
Comms::~Comms(){ //内存指针回收形式
    for(int i=0; i<mcount; i++){
        if(pCes[i]!=NULL){
            delete pCes[i];//可能是空指针,会报错
            pCes[i] = NULL;
        }
    }//先回收每个指针,再回收每个指针指向的数组
    if(pCes!=NULL)  delete []pCes;
}

CommEntry.h

#pragma once
#include<bits/stdc++.h>
using namespace std;
class CommEntry{
public:
    CommEntry(int num = 20); // 设置缺省构造函数
    virtual void InputCommEntry();
    virtual void OutputCommEntry() const;
    virtual void SetTel(string tel);
    virtual string GetName() const ;
    virtual string GetTel(int iNum) const ;
    virtual  ~CommEntry();//父类定义虚析构,析构时先析构派生类再析构父类,不然直接析构父类
      //多态父类虚函数实现了可以不写
      //纯虚函数基类不再使用->抽象类
protected://子类可访问
   string mName;
    int mtelCount;
    int mmaxCount;
    string *mTel;
    string *mtelType;
};

CommEntry.cpp

#include"CommEntry.h"
CommEntry::CommEntry(int up){
    mmaxCount = up;
    mTel = new string[mmaxCount];  // 堆区动态开辟空间,需要自动回收
    mtelType = new string[mmaxCount];  //指针指向新开辟数组开头
}
void CommEntry::InputCommEntry(){
    cout << "请输入该联系人的电话个数:";
    cin >> mtelCount ;
    cout << "请输入姓名为:" << endl;
    cin >> mName;
    int i,j;
    for ( i = 0; i < mtelCount; i++){
        cout << "请输入第" << i+1 << "个电话类型为:" << endl;
        while (cin >> mtelType[i]){
            for ( j = 0; j < i; j++)
                if (mtelType[i] == mtelType[j]) break;
            if (j < i) cout << "该电话类型已经存在! 请重新输入。" << endl;
            else break;
        }
        cout << "请输入第" << i+1 << "个电话为:" << endl;
        cin >> mTel[i];
    }
}
void CommEntry::OutputCommEntry () const {
    cout << "姓名: " << GetName() << "\n";
    for(int i=0; i<mtelCount; i++) {
        cout << i+1 << "." << mtelType[i]
             << "电话:"<< GetTel(i) << "\n";
    }
    if ( mtelType[mtelCount] == "指定电话:  ")
        cout << mtelType[mtelCount] << mTel[mtelCount] << endl;
    cout << "------------------------------\n";
}
string CommEntry::GetName() const {
    return mName;
}
string CommEntry::GetTel(int iNum) const {
    return mTel[iNum];
}
void CommEntry::SetTel(string tel) {
    mTel[mtelCount] = tel;
    mtelType[mtelCount] = "指定电话:  ";
}
CommEntry::~CommEntry() {
    delete []mTel;
    delete []mtelType;//程序结束时调用析构函数
    cout<<"一般"<<endl;
}

FriendEntry.h

#pragma once
#include<bits/stdc++.h>
#include"CommEntry.h"
using namespace std;
class FriendEntry:public CommEntry{
public:
    FriendEntry(int num = 20); // 设置缺省构造函数
    virtual void InputCommEntry();
    virtual void OutputCommEntry() const;
    virtual void SetTel(string tel);
    virtual string GetName() const ;
    virtual string GetEmail() const ;
    virtual string GetTel(int iNum) const ;
    ~FriendEntry();
protected:
    string mName;
    int mtelCount;
    int mmaxCount;
    string *mTel;
    string *mtelType;
    string mEmail;
};

FriendEntry.cpp

#include"FriendEntry.h"
FriendEntry::FriendEntry(int up){
    mmaxCount = up;
    mTel = new string[mmaxCount];  // 堆区动态开辟空间,需要自动回收
    mtelType = new string[mmaxCount];  //指针指向新开辟数组开头
}
void FriendEntry::InputCommEntry() {
    cout << "请输入该联系人的电话个数:";
    cin >> mtelCount ;
    cout << "请输入姓名为:" << endl;
    cin >> mName;
    int i,j;
    for ( i = 0; i < mtelCount; i++) {
        cout << "请输入第" << i+1 << "个电话类型为:" << endl;
        while (cin >> mtelType[i]){
            for ( j = 0; j < i; j++)
                if (mtelType[i] == mtelType[j]) break;
            if (j < i) cout << "该电话类型已经存在! 请重新输入。" << endl;
            else break;
        }
        cout << "请输入第" << i+1 << "个电话为:" << endl;
        cin >> mTel[i];
        cout << "请输入第" << i+1 << "个邮箱为:" << endl;
        cin >> mEmail;
    }
}
void FriendEntry::OutputCommEntry () const {
    cout << "姓名: " << GetName() << "\n";
    cout << "邮箱: " << GetEmail()  << "\n";
    for(int i=0; i<mtelCount; i++) {
        cout << i+1 << "." << mtelType[i]
             << "电话:"<< GetTel(i) << "\n";
    }
    if ( mtelType[mtelCount] == "指定电话:  ")
        cout << mtelType[mtelCount] << mTel[mtelCount] << endl;
    cout << "-------------------------------\n";
}
string FriendEntry::GetName() const{
    return mName;
}
string FriendEntry::GetEmail() const {
    return mEmail;
}
string FriendEntry::GetTel(int iNum) const {
    return mTel[iNum];
}
void FriendEntry::SetTel(string tel){
    mTel[mtelCount] = tel;
    mtelType[mtelCount] = "指定电话:  ";
}
FriendEntry::~FriendEntry(){
    delete []mTel;
    delete []mtelType;//程序结束时调用析构函数
    cout<<"朋友"<<endl;//先析构派生类还要析构父类
}

9.实验九-非多态文件版的通讯录

通讯录管理程序
问题描述:通讯录管理程序。通讯录是由通讯录条目组成的。通讯录总条目数。通讯录中现有多少条。可以输入通讯录、可以输出通讯录、可以查找、修改。 ==要求:可以将条目输出到文件中。可以从文件读取数据。==
Comms
-pCe : CommEntry *
-maxCount : int
-count : int
+inputAll() : void
+inputAllFromFile(istream in) : void
+outputAll() : void
+outputAllToFile(ostream out) : void
+find(string nm) : CommEntry
+modify(string nm, string t) : void
CommEntry
-name : string
-tel : string
+input() : void
+inputFromFile(istream in) : void
+output() : void
+outputToFile(ostream out) : void
+setName(string nm) : void
+setTle(string t) : void
+getName() : string
+getTel() : string

要求:
1.输入通讯录
2.输出通讯录
3.查找姓名
4.修改(输入姓名,修改其电话)
5.输出到文件
6.从文件中读取数据
0.退出
技术要点:
在这里插入图片描述

class CommEntry{
public:
   CommEntry();
   void input();
   void inputFromFile(istream in); 
   void output();
   void outputToFile(ostream &out);
   void setName(string nm);
   void setTel(string t);
   string getName();
   string getTel();

private:
   string name;
   string tel;

};

void CommEntry::output(){
    cout<<"Name:"<<name<<endl;
    cout<<"Tel:"<<tel<<endl;
}

          case 5:{
               ofstream file1;
               file1.open("record.txt");
               comms.outputAllFromFile(file1);
               file1.close();
               break;
          }

实验作业:
1、如何从数据文件中读取数据?提示:改造输入函数,或是编写从文件读取的函数。
参考代码:
main.cpp

#include"CommEntry.h"
#include"Comms.h"
#define FILENAME  "comFile.txt"
int  main() {
    Comms ceZS(20);
    int iChoice = 1;
    while (iChoice != 0) {
        iChoice = ceZS.Menu();
        switch ( iChoice) {
        case 1:
            if ( ceZS.IfEmpty()) ceZS.InputAll();
            else cout << "通讯录已存在!" << endl;
            break;
        case 2:
            if ( !ceZS.IfEmpty()) ceZS.OutputAll();
            else cout << "当前通讯录为空!" << endl;
            break;
        case 3:
            if ( !ceZS.IfEmpty()) {
                cout << "请输入要查找的姓名 :" << endl;
                string nm;
                cin >> nm;
                int num = ceZS.Find(nm);
                if (num != -1)
                    cout << "该姓名为通讯录中第" << num+1 << "条" << endl;
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 4:
            if ( !ceZS.IfEmpty()) {
                string nm, tel;
                cout << "请输入要修改的姓名:" << endl;
                cin >> nm;
                cout << "请输入要设置的指定电话为:" << endl;
                cin >> tel;
                ceZS.Modify(nm,tel);
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 5:
            if ( !ceZS.IfEmpty()) {
                ofstream ofs;
                ofs.open(FILENAME,ios::out);
                ceZS.outputAllToFile(ofs);
                ofs.close();//从头开始写,执行覆盖原则
            }
            else cout << "当前通讯录为空!" << endl;
            break;
        case 6: {
            ifstream ifs;
            ifs.open(FILENAME,ios::in);
            ceZS.inputAllFromFile(ifs);
            ifs.close();
        }
        break;
        case 0:
            cout << "欢迎再次使用!";
            return 0;
        }
        system("pause");
        system("cls");
    }
    return 0;
}

Comms.h

#pragma once
#include<bits/stdc++.h>
#include"CommEntry.h"
using namespace std;
class Comms {
public:
    Comms(int up = 10);
    ~Comms();
    int Menu();
    void InputAll();
    void inputAllFromFile(ifstream &ifs);
    void OutputAll();
    void outputAllToFile(ofstream &out);
    int Find(string nm);
    void Modify(string nm, string t);
    bool IfEmpty();
private:
    CommEntry * mpCe;
    int mmaxCount;
    int mcount;
    bool mEmpty;
};


Comms.cpp

#include"Comms.h"
int Comms::Menu(){
    string ch;
    while(true) {
        cout << "----------非多态文件版的通讯录--------\n";
        cout << "1.输入通讯录\n";
        cout << "2.输出通讯录\n";
        cout << "3.查找姓名(输出在通讯录中的位置)\n";
        cout << "4.修改(输入姓名,设置指定电话)\n";
        cout << "5.输出到文件\n";
        cout << "6.从文件中读取数据\n";
        cout << "0.退出\n";
        cout << "--------------------------------------\n";
        cout << "请输入您的选择(0-6):\n";
        while (getline(cin,ch)) if (ch.length()) break;
        if ('0' <= ch[0]&&ch[0] < '7' && ch.length() == 1) return int(ch[0]-'0');
        cout << "输入无效,请再次输入!" << endl;
        system("pause");
        system("cls");
    }
}
Comms::Comms( int up) {
    mmaxCount = up;
    mpCe = new CommEntry[mmaxCount];
    mcount = 0;
    mEmpty = true; // 通讯录设置为空
}
void Comms:: InputAll() {
    int iCount;
    cout << "请输入要输入的通讯录的条目个数:";
    cin >> iCount;
    if (0 < iCount && iCount < mmaxCount-mcount ) { // 判断是否合法
        for (int i =  mcount ; i < mcount+iCount; i++){
            cout << "请输入第" << i+1 ;
            mpCe[i].InputCommEntry();
        }
        mEmpty = false; // 通讯录设置为存在
        cout << "输入成功! " << endl;
        mcount += iCount;
    }
    else cout << "输入无效! " << endl;
}
void Comms::inputAllFromFile(ifstream &ifs) {
    if(!ifs.is_open()) cout << "文件不存在" << endl;
    string ch;
    ifs >> ch;
    if(ifs.eof()) cout << "文件为空" << endl;
    else{
        int recordcout = 0;
        while(getline(ifs,ch)) recordcout++;
        if (recordcout/5+mcount >= mmaxCount) cout << "内存不足!" << endl;
        else{
            ifs.clear(); //清除eof()文件末尾的标志
            ifs.seekg(0,ios::beg);//重头开始读文件
            int cnt = mcount;
            while(ifs >> ch){
                mpCe[cnt].inputFromFile(ifs);
                cnt++;
            };
            mcount = cnt;
            mEmpty = false;
            cout << "读取文件成功!" << endl;
        }
    }
}
void Comms::outputAllToFile(ofstream &ofs) {
    for(int i = 0; i < mcount; i++){
        mpCe[i].outputToFile(ofs);
    }
}
void Comms::OutputAll() {
    cout << "\n------------- 输出通讯录 -------------\n";
    for (int i = 0; i < mcount; i++) {
        cout << "第" << i+1 << "个联系人:  " << endl;
        mpCe[i].OutputCommEntry();
    }
}
int Comms::Find(string nm) {
    for (int i = 0; i < mcount; i++) {
        if (mpCe[i].GetName() == nm) return i;
    }
    cout << "该姓名不存在!"<< endl;
    return -1;
}
void Comms::Modify(string nm, string t) {
    int num = Find(nm);
    if(num != -1){
        mpCe[num].SetTel(t);
        cout << " 指定电话设置成功! " << endl;
    }
}
bool Comms::IfEmpty() {
    return mEmpty;
}
Comms::~Comms(){
    delete []mpCe;//内存回收先调用 CommEntry(数据成员)的析构函数
}

CommEntry.h

#pragma once
#include<bits/stdc++.h>
using namespace std;
class CommEntry {
public:
    CommEntry(int num = 20); // 设置缺省构造函数
    void InputCommEntry();
    void inputFromFile(ifstream &ifs);
    void OutputCommEntry() const;
    void outputToFile(ofstream &ofs);
    void SetTel(string tel);
    string GetName() const ;
    string GetTel(int iNum) const ;
    ~CommEntry();
private:
    string mName;
    int mtelCount;
    int mmaxCount;
    string *mTel;;
    string *mtelType;
};

CommEntry.cpp

#include"CommEntry.h"
CommEntry::CommEntry(int up){
    mmaxCount = up;
    mTel = new string[mmaxCount];  // 堆区动态开辟空间,需要自动回收
    mtelType = new string[mmaxCount];  //指针指向新开辟数组开头
}
void CommEntry::inputFromFile(ifstream &ifs) {
    string str;//读取文件中中文字符串与分割线字符串
    ifs >> mtelCount >> str >> mName;
    for ( int i = 0; i < mtelCount; i++)
        ifs >> mtelType[i] >> str >> mTel[i];
    ifs>> str >> str ;
    if ( str != "无" ){
        mTel[mtelCount] = str ;
        mtelType[mtelCount] = "指定电话:";
    }
    ifs >> str ;//读取分割线
}
void CommEntry::outputToFile(ofstream &ofs){
    ofs << "联系人的电话个数:  " << mtelCount<< endl;
    ofs << "姓名:  " << GetName() << "\n";
    for(int i = 0; i < mtelCount; i++) {
        ofs <<  mtelType[i] << " " << "电话:" << " " << GetTel(i) << "\n";
    }
    ofs << "指定电话: " ;
    if ( mtelType[mtelCount] == "指定电话:")  ofs << mTel[mtelCount] << "\n";
    else  ofs << "无" << "\n";
    ofs << "--------------------------------------\n";
}
void CommEntry::InputCommEntry() {
    cout << "个联系人的电话个数:";
    cin >> mtelCount ;
    cout << "请输入姓名为:" << endl;
    cin >> mName;
    int i,j;
    for ( i = 0; i < mtelCount; i++){
        cout << "请输入第" << i+1 << "个电话类型为:" << endl;
        while (cin >> mtelType[i]) {
            for ( j = 0; j < i; j++)
                if (mtelType[i] == mtelType[j]) break;
            if (j < i) cout << "该电话类型已经存在! 请重新输入。" << endl;
            else break;
        }
        cout << "请输入第" << i+1 << "个电话为:" << endl;
        cin >> mTel[i];
    }
}
void CommEntry::OutputCommEntry () const {
    cout << "姓名: " << GetName() << "\n";
    for(int i=0; i<mtelCount; i++) {
        cout << i+1 << "." << mtelType[i]
             << "电话:"<< GetTel(i) << "\n";
    }
    if ( mtelType[mtelCount] == "指定电话:")
        cout << mtelType[mtelCount] << mTel[mtelCount] << endl;
    cout << "--------------------------------------\n";
}
string CommEntry::GetName() const {
    return mName;
}
string CommEntry::GetTel(int iNum) const {
    return mTel[iNum];
}
void CommEntry::SetTel(string tel) {
    mTel[mtelCount] = tel;
    mtelType[mtelCount] = "指定电话:";
}
CommEntry::~CommEntry() {
    delete []mTel;
    delete []mtelType;//程序结束时调用析构函数
}

不足与疑惑欢迎交流讨论~: )

hhhh

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值