模拟电信计费系统
3.8模拟电信计费系统的设计与实现
3.8.1设计题目及要求
模拟电信计费系统的设计与实现
要求:(1)计费功能。根据存放在源数据文件中的通话记录和长途费率文件对每一条通话记录计算其通话费用,并将结果保存在费用文件中。其
中:
通话费的计算方法如下:
通话费=长途电话费+本地电话费
长途电话费=费率(元/分钟)×通话时长(分钟)
(通话时长不满1分钟的按1分钟计算)
本地电话费为:3分钟以内0.5元,以后每3分钟递增0.2元。
(2)话费查询。输入一个电话号码,从费用文件中统计该电话号码
的所有本地话费、长途话费,并从用户文件中查找其用户名,最后在
屏幕上显示:
用户名电话号码本地话费长途话费话费总计
(3)话单查询。输入一个电话号码,查询并在屏幕显示该用户的所有通话记录,格式为:
用户名主叫电话号码被叫电话号码通话时长
3.8.2设计思想及程序流程框图
程序设计大致思路:
1.本系统的输入输出文件
本系统的输入文件有三个:
(1)源数据文件(hd.dat)
存放:主叫区号主叫电话号码被叫区号被叫电话号码通话时长(秒)每次通话作为一条记录,占源数据文件的一行。
每条记录中各数据之间以空格间隔,例如:025 ******** 010 ********
90
每个电话号码可以有多次通话记录。
如果主、被叫区号相同,则通话记录为本地通话记录;否则为长途通话记录。
(2)长话费率文件(fl.dat)
存放:区号费率
例如:010 1.20 表示从本地打往区号为010的地区每分钟收费1.20元。
(3)用户文件(yh.dat)
存放:电话号码用户姓名
例如: 83491234 张明
本系统的输出文件有一个:
费用文件(fy.dat)
存放:主叫电话号码通话类型话费金额
其中,通话类型表示本次通话是长途还是本地。
2.系统输入数据
hd.dat—有20条通话记录,分别是:fl.dat 有4条记录025 ******** 025 ******** 70 010 1.20 025 ******** 010 ******** 236 020 1.20
025 ******** 025 ******** 310 021 0.80
025 ******** 0571 ******** 100 0571 1.00
025 ******** 021 ******** 50
025 ******** 025 ******** 80
025 ******** 025 ******** 115 yh.dat有5条记录
025 ******** 025 ******** 47 83491234 张明
025 ******** 010 ******** 93 84927038 李小红
025 ******** 010 ******** 792 87216340 王励
025 ******** 0571 ******** 931 83492200 赵强
025 ******** 025 ******** 580 58120321 杨冬
025 ******** 025 ******** 358
025 ******** 021 ******** 197
025 ******** 025 ******** 256
025 ******** 010 ******** 193
025 ******** 025 ******** 320
025 ******** 025 ******** 270
025 ******** 025 ******** 231
025 ******** 025 ******** 72
3.数据结构(可用C++实现)
三个类:话单(callist)、费用(charge)和用户(user)
两个常量:存放本地费率和递增量
(1)话单类
数据成员:主叫区号、主叫电话号码、被叫区号、被叫电话号码、通话时长
数据类型
属性(私有、保护、公有)
方法:构造函数和析构函数
从源数据文件读入通话数据
显示一次通话数据
取主叫区号
取主叫电话号码等等
(2)费用类——从话单类派生
数据成员:通话类型、通话费用
数据类型
属性(私有、保护、公有)
方法:构造函数和析构函数
从费用文件读入费用数据
向费用文件输出数据
屏幕显示费用
求通话费用
求通话类型
取(返回)通话类型
取通话费用等等
(3)用户类
数据成员:姓名、电话号码
数据类型
属性(私有、保护、公有)
方法:设置用户的电话号码
查询用户名
设置用户名
查询用户的电话号码
显示用户名和电话号码等等
(1)话单类(CallList)
class CallList
{
protected:
char *ZCode; //主叫区号
char *ZNum; //主叫号码
char *BCode; //被叫区号
char *BNum; //被叫号码
int Time; //通话时长(秒)
public:
CallList(char *zcode=NULL,char *znum=NULL,
char *bcode=NULL,char *bnum=NULL,int time=0);
~CallList();
void Set(char *zcode=NULL,char *znum=NULL,
char *bcode=NULL,char *bnum=NULL,int time=0);
void Print();
char *getZC();
char *getZN();
char *getBC();
char *getBN();
int getTime();
};
(2)费用类(Charge)——从话单类派生
class Charge:public CallList //公有继承
{
protected:
int CallStyle; //为0时表示本地通话,为1时表示长途通话float Expense; //话费
public:
Charge(char *zcode=NULL,char *znum=NULL,char *bcode=NULL, char *bnum=NULL,int time=0,int callstyle=0,float exp=0);
void Set(char *zcode=NULL,char *znum=NULL,
char *bcode=NULL,char *bnum=NULL,int time=0);
void ComputeSty();
int GetStyle();
float GetExp();
void PrintExp();
};
(3)用户类(Consumer)
class Consumer
{
protected:
char *Name; //用户姓名
char *Num; //用户电话号码
public:
Consumer(char *name=NULL,char *num=NULL);
~Consumer();
void SetName(char *name=NULL);
void SetNum(char *num=NULL);
char *GetName();
char *GetNum();
void Print();
};
(4)费率类(Rate)
class Rate
{
protected:
char *Code; //区号
float rate; //费率
public:
Rate(char *code=NULL,float rat=0);
~Rate();
void Set(char *code=NULL,float ra=0);
char *GetCode();
float GetRate();
void printRate();
};
根据自顶向下,逐步细化的程序设计思想,考虑将程序分为五大模块:文件
导入模块,话费计算模块,文件导出模块,查询模块以及确认退出模块。由此所得的程序结构图大致如下所示:
由系统结构图得到相应各个主要模块的的函数如下:
1.char Menu(char *ptr);
//函数功能:菜单显示并获得键盘选择
//函数参数:字符型指针ptr,表示菜单选择时输入字符串地址
//函数返回值:输入的键盘的ASCII码对应字符
2.Rate *InputRate(int &total);
//函数功能:从文件中读取费率文件并做相关异常处理
//函数参数:整型total,表示费率的总数
//函数返回值:Rate型,表示对象数组的首地址
3.Consumer *InputConsumer(int &total);
//函数功能:从文件中读取用户文件并做相关异常处理
//函数参数:整型total,表示用户的总数
//函数返回值:Consumer型,表示对象数组的首地址
4.Charge *InputCharge(int &total);
//函数功能:从文件中读取通话记录文件并做相关异常处理
//函数参数:整型total,表示通话记录的总数
//函数返回值:Charge型,表示对象数组的首地址
5.int ComputeExp(Charge *ptc=NULL,Rate *ptr=NULL,
int totalCharge=0,int totalRate=0);
//函数功能:计算每个通话记录的话费
//函数参数:Charge型指针ptc,表示通话记录对象数组的首地址
// Rate型指针ptr,表示费率对象数组的首地址
// 整型totalCharge,表示通话记录总数
// 整形totalRate,表示费率总数
//函数返回值:整型,0表示异常退出;1表示正常退出
6.int Output(Charge *point=NULL,int total=0);
//函数功能:导出数据到文件保存
//函数参数:Marks指针point,表示对象数组的首地址
// 整型total,表示学生总数
//函数返回值:整形,0表示正常输出;1表示异常输出
7.int PrintFY(Charge *point=NULL,int total=0);
//函数功能:显示导出到文件保存的数组
//函数参数:Charge指针,表示通话记录对象数组的首地址
// 整型total,表示通话记录总数
//函数返回值:整形,0表示正常输出;1表示异常输出
8.int FindExp(Charge *ptch=NULL,Consumer *ptco=NULL, int totalCharge=0,int totalConsumer=0);
//函数功能:话费查询
//函数参数:Charge型指针ptch,表示通话记录对象数组的首地址// Consumer型指针ptco,表示用户对象数组的首地址// 整型totalCharge,表示通话记录总数
// 整形totalConsumer,表示用户总数
//函数返回值:整型,1表示异常退出;0表示正常退出
9.int FindList(Charge *ptch=NULL,Consumer *ptco=NULL, int totalCharge=0,int totalConsumer=0);
//函数功能:话单查询
//函数参数:Charge型指针ptch,表示通话记录对象数组的首地址// Consumer型指针ptco,表示用户对象数组的首地址// 整型totalCharge,表示通话记录总数
// 整形totalConsumer,表示用户总数
//函数返回值:整型,1表示异常退出;0表示正常退出
10.void Exit(char *p1,Rate *p2,Consumer *p3,Charge *p4);
//函数功能:选择是否退回DOS,确定后释放相关内存
//函数参数:字符型指针p1,表示Menu模块中输入选择字符串的首地址// Rate型指针p2,表示费率对象数组的首地址
// Consumer型指针p3,表示用户对象数组的首地址
// Charge型指针p4,表示通话记录对象数组的首地址
//函数返回值:无
3.8.3逻辑功能程序
1.Header Files
(1) .CallList.h
#include
class CallList
{
protected:
char *ZCode; //主叫区号
char *ZNum; //主叫号码
char *BCode; //被叫区号
char *BNum; //被叫号码
int Time; //通话时长(秒)
public:
CallList(char *zcode=NULL,char *znum=NULL,
char *bcode=NULL,char *bnum=NULL,int time=0);
~CallList();
void Set(char *zcode=NULL,char *znum=NULL,
char *bcode=NULL,char *bnum=NULL,int time=0);
void Print();
char *getZC();
char *getZN();
char *getBC();
char *getBN();
int getTime();
};
(2).Charge.h
#include "CallList.h"
class Rate;
class Consumer;
class Charge:public CallList //公有继承
{
protected:
int CallStyle; //为0时表示本地通话,为1时表示长途通话float Expense; //话费
public:
Charge(char *zcode=NULL,char *znum=NULL,char *bcode=NULL, char *bnum=NULL,int time=0,int callstyle=0,float exp=0);
void Set(char *zcode=NULL,char *znum=NULL,
char *bcode=NULL,char *bnum=NULL,int time=0);
void ComputeSty();
int GetStyle();
float GetExp();
void PrintExp();
friend Charge *InputCharge(int &total); //友元声明
friend int ComputeExp(Charge *ptc,Rate *ptr,
int totalCharge,int totalRate);
friend int FindExp(Charge *ptch,Consumer *ptco,
int totalCharge,int totalConsumer);
friend int FindList(Charge *ptch,Consumer *ptco,
int totalCharge,int totalConsumer);
};
(3).Consumer.h
#include
class Charge; //类声明
class Consumer
{
protected:
char *Name; //用户姓名
char *Num; //用户电话号码
public:
Consumer(char *name=NULL,char *num=NULL);
~Consumer();
void SetName(char *name=NULL);
void SetNum(char *num=NULL);
char *GetName();
char *GetNum();
void Print();
friend Consumer *InputConsumer(int &total); //友元声明
friend int FindExp(Charge *ptch,Consumer *ptco,
int totalCharge,int totalConsumer);
friend int FindList(Charge *ptch,Consumer *ptco,
int totalCharge,int totalConsumer);
};
(4).Rate.h
#include
class Charge; //类声明
class Rate
{
protected:
char *Code; //区号
float rate; //费率
public:
Rate(char *code=NULL,float rat=0);
~Rate();
void Set(char *code=NULL,float ra=0);
char *GetCode();
float GetRate();
void printRate();
friend Rate *InputRate(int &total); //友元声明friend int ComputeExp(Charge *ptc,Rate *ptr,
int totalCharge,int totalRate); };
2.Source Files
(1) .CallList.cpp
#include "CallList.h"
#include
CallList::CallList(char *zcode,char *znum,char *bcode,
char *bnum,int time)
{
ZCode=zcode;
ZNum=znum;
BCode=bcode;
BNum=bnum;
Time=time;
}
CallList::~CallList()
{
delete ZCode;
delete ZNum;
delete BCode;
delete BNum;
}
void CallList::Set(char *zcode,char *znum,
char *bcode,char *bnum,int time)
{
ZCode=new char[strlen(zcode)+1];
strcpy(ZCode,zcode);
ZNum=new char[strlen(znum)+1];
strcpy(ZNum,znum);
BCode=new char[strlen(bcode)+1];
strcpy(BCode,bcode);
BNum=new char[strlen(bnum)+1];
strcpy(BNum,bnum);
Time=time;
}
void CallList::Print()
{
cout<<" "< < char *CallList::getZC() { return ZCode; } char *CallList::getZN() { return ZNum; } char *CallList::getBC() { return BCode; } char *CallList::getBN() { return BNum; int CallList::getTime() { return Time; } (2) .Charge.cpp #include "Charge.h" #include Charge::Charge(char *zcode,char *znum,char *bcode, char *bnum,int time,int callstyle,float exp) :CallList(zcode,znum,bcode,bnum,time) { CallStyle=callstyle; Expense=exp; } void Charge::Set(char *zcode,char *znum, char *bcode,char *bnum,int time) { CallList::Set(zcode,znum,bcode,bnum,time); } void Charge::ComputeSty() { if(strcmp(ZCode,BCode)==0) CallStyle=0; else CallStyle=1; } int Charge::GetStyle() { return CallStyle; } float Charge::GetExp() { return Expense; } void Charge::PrintExp() cout< } (3) .Consumer.cpp #include "Consumer.h" #include Consumer::Consumer(char *name,char *num) { Name=name; Num=num; } Consumer::~Consumer() { delete Name; delete Num; } char *Consumer::GetName() { return Name; } char *Consumer::GetNum() { return Num; } void Consumer::SetName(char *name) { Name=new char[strlen(name)+1]; strcpy(Name,name); } void Consumer::SetNum(char *num) { Num=new char[strlen(num)+1]; strcpy(Num,num); } void Consumer::Print() { cout< (5).Rate.cpp #include "Rate.h" #include Rate::Rate(char *code,float rat) { Code=code; rate=rat; } Rate::~Rate() { delete Code; } void Rate::Set(char *code,float rat) { Code=new char[strlen(code)+1]; strcpy(Code,code); rate=rat; } char *Rate::GetCode() { return Code; } float Rate::GetRate() { return rate; } void Rate::printRate() { cout< } (6).TeleExpSystem.cpp #include "Consumer.h" #include "Charge.h" #include "Rate.h" #include #include #include #include #include char Menu(char *ptr); //函数声明 Rate *InputRate(int &total); Consumer *InputConsumer(int &total); Charge *InputCharge(int &total); int ComputeExp(Charge *ptc=NULL,Rate *ptr=NULL, int totalCharge=0,int totalRate=0); int Output(Charge *point=NULL,int total=0); int PrintFY(Charge *point=NULL,int total=0); int FindExp(Charge *ptch=NULL,Consumer *ptco=NULL, int totalCharge=0,int totalConsumer=0); int FindList(Charge *ptch=NULL,Consumer *ptco=NULL, int totalCharge=0,int totalConsumer=0); void Exit(char *p1,Rate *p2,Consumer *p3,Charge *p4); int main() { char c; //接受菜单选择字符 int TotalRate=0; //费率总数 int TotalConsumer=0; //用户总数 int TotalCharge=0; //通话记录总数 Rate *ptRate=NULL; Consumer *ptConsumer=NULL; Charge *ptCharge=NULL; char *pt=NULL; while(1) { c=Menu(pt); //调用菜单函数 switch(c) { case '1': ptRate=InputRate(TotalRate); ptConsumer=InputConsumer(TotalConsumer); ptCharge=InputCharge(TotalCharge); break; case '2': ComputeExp(ptCharge,ptRate,TotalCharge,TotalRate); break; case '3': Output(ptCharge,TotalCharge); PrintFY(ptCharge,TotalCharge); break; case '4': FindExp(ptCharge,ptConsumer,TotalCharge,TotalConsumer); break; case '5': FindList(ptCharge,ptConsumer,TotalCharge,TotalConsumer); break; case '6': Exit(pt,ptRate,ptConsumer,ptCharge); //确认退出模块 break; default: cout<<"Input Error!"; break; } cout<<"\nPress anykey to main menu."< getch(); // while (!kbhit()); //检查当前是否有键盘按下(有回显) } return 0; } //函数功能:菜单显示并获得键盘选择 //函数参数:字符型指针ptr,表示菜单选择时输入字符串地址 //函数返回值:输入的键盘的ASCII码对应字符 char Menu(char *ptr) { cout<<"\t*************************************************\n"; cout<<"\t 模拟电信计费系统\n"; cout<<"\t*************************************************\n"; cout<<"\t 1. 费率、用户、通话记录文件\n"; cout<<"\t 2. 计算话费\n"; cout<<"\t 3. 计费结果\n"; cout<<"\t 4. 话费查询\n"; cout<<"\t 5. 话单查询\n"; cout<<"\t 6. 退出\n"; cout<<"\t*************************************************\n"; BACK: cout<<"请按照序号选择操作:"< char *sign=new char[10]; cin>>sign; ptr=sign; if(strlen(sign)>1) { cout<<"Input Error!\n"; goto BACK; } return *(sign); } //函数功能:从文件中读取费率文件并做相关异常处理 //函数参数:整型total,表示费率的总数 //函数返回值:Rate型,表示对象数组的首地址 Rate *InputRate(int &total) { char *add=new char[20]; //申请空间存放待打开文件地址 add="d:\\fl.dat"; //方便文件测试,实际操作时请使用下面标示//的代码 cout<<"成功导入费率文件"< // cout<<"请正确输入费率文件的详细地址:"< // gets(add); ifstream fin(add); if(!fin) { cout<<"Can't open the file!"< return NULL; } float rate=0; char *code=new char[10]; fin>>total; Rate *ptr=new Rate[total]; cout<<"区号"<<" "<<"费率(元/分钟)"< for(int i=0;i { fin>>code; fin>>rate; (ptr+i)->Set(code,rate); (ptr+i)->printRate(); } fin.close(); // delete add; return ptr; } //函数功能:从文件中读取用户文件并做相关异常处理 //函数参数:整型total,表示用户的总数 //函数返回值:Consumer型,表示对象数组的首地址 Consumer *InputConsumer(int &total) { char *add=new char[20]; //申请空间存放待打开文件地址 add="d:\\yh.dat"; //方便文件测试,实际操作时请使用下面标示//的代码 cout<<"成功导入用户文件"< // cout<<"请正确输入用户文件的详细地址:"< // gets(add); ifstream fin(add); if(!fin) { cout<<"Can't open the file!"< return NULL; } char *num=new char[10]; char *name=new char[10]; fin>>total; Consumer *ptr=new Consumer[total]; cout<<"电话号码"<<" "<<"用户姓名"< for(int i=0;i { fin>>num; fin>>name; (ptr+i)->SetNum(num); (ptr+i)->SetName(name); (ptr+i)->Print(); } fin.close(); // delete add; return ptr; } //函数功能:从文件中读取通话记录文件并做相关异常处理 //函数参数:整型total,表示通话记录的总数 //函数返回值:Charge型,表示对象数组的首地址 Charge *InputCharge(int &total) { char *add=new char[20]; //申请空间存放待打开文件地址 add="d:\\hd.dat"; //方便文件测试,实际操作时请使用下面标示//的代码 cout<<"成功导入通话记录"< // cout<<"请正确输入通话记录文件的详细地址:"< // gets(add); ifstream fin(add); if(!fin) { cout<<"Can't open the file!"< return NULL; } int time=0; char *zcode=new char[10]; char *znum=new char[10]; char *bcode=new char[10]; char *bnum=new char[10]; fin>>total; Charge *ptr=new Charge[total]; cout<<"主叫区号"<<" "<<"主叫号码"<<" " <<"被叫区号"<<" "<<"主叫号码"<<" " <<"通话时长(秒)"< for(int i=0;i { fin>>zcode>>znum>>bcode>>bnum>>time; (ptr+i)->Set(zcode,znum,bcode,bnum,time); (ptr+i)->Print(); } fin.close(); // delete add; return ptr; } //函数功能:计算每个通话记录的话费 //函数参数:Charge型指针ptc,表示通话记录对象数组的首地址 // Rate型指针ptr,表示费率对象数组的首地址 // 整型totalCharge,表示通话记录总数 // 整形totalRate,表示费率总数 //函数返回值:整型,0表示异常退出;1表示正常退出 int ComputeExp(Charge *ptc,Rate *ptr,int totalCharge,int totalRate) { if(ptc==NULL||totalCharge==0) { cout<<"没有通话记录,无法计算!"< return 0; } for(int i=0;i { int time=0; float fl=0; float temp=0.0; time=(ptc+i)->Time/60; if((ptc+i)->Time%60>=0) time++; (ptc+i)->ComputeSty(); if((ptc+i)->CallStyle==0) //计算本地通话费 { if(time<=3) temp=0.5; else { int n=time/3; int m=time%3; for(int j=0;j { temp=temp+0.5+float(j)*0.2; } if(m!=0) temp=temp+0.5+float(j)*0.2; } (ptc+i)->Expense=temp; } else //计算长途话费 { for(int x=0;strcmp((ptc+i)->BCode,(ptr+x)->Code) &&x { } fl=(ptr+x)->rate; temp=float(time)*fl; (ptc+i)->Expense=temp; } } cout<<"话费计算结束!"< return 1; } //函数功能:导出数据到文件保存 //函数参数:Marks指针point,表示对象数组的首地址 // 整型total,表示学生总数 //函数返回值:整形,0表示正常输出;1表示异常输出 int Output(Charge *point,int total) { if(total==0||point==NULL) { cout<<"没有通话记录,不能输出!"< return 1; } char *add=new char[20]; //测试代码,可以使用下面的注释代码代替 add="d:\\fy.dat"; // cout<<"Please input the address you want to store:"< // gets(add); ofstream fout(add); //打开文件输出流 if(!fout) { cout<<"Can't open output file!"< return 1; } fout<<" 主叫号码"<<" 通话类型"<<" 话费"< for(int i=0;i { fout<<" "<<(point+i)->getZN()<<" \t"; if((point+i)->GetStyle()) { fout<<"长途"<<" \t"; } else { fout<<"本地"<<" \t"; } fout<<(point+i)->GetExp()< } fout.close(); cout<<"文件已成功输出到:"< // delete add; return 0;