设计一个程序,其中有3个类CBank、BBank、GBank,分别为中国银行类,工商银行类和农业银行类。每个类都包含一个私有数据成员balance用于存放储户在该行的存款数,另有一个友元函数Total用于计算储户在这3家银行中的总存款。类结构图如图6-1所示。

因为觉得类的私有数据成员只有balance太不正常了,因此增加了成员Id和Key,分别表示账户号码和密码。只有当三个银行的Id和Key都相同时,用户才能访问balance成员,Total函数才能成功执行。

代码如下:

 #include<iostream>
using namespace std;
#include<string>
class BBank;
class GBank; //Total同时是三个类的友元函数,必须在创建类前先声明所有类 class CBank //CBank类的声明
{public:
CBank(char*,char*,double); //构造函数原型声明
friend void Total(CBank &,BBank &,GBank &); //声明Total函数为CBank类的友元函数
private:
char id[]; //账户名
char key[]; //6位密码
double balance; //银行存款
}; CBank::CBank(char Id[],char Key[],double Balance) //构造函数的类外定义
{
for(int i=;i<;i++)
id[i]=Id[i];
for(int j=;j<;j++)
key[j]=Key[j];
balance=Balance;
} class BBank //BBank类的声明
{public:
BBank(char*,char*,double); //构造函数原型声明
friend void Total(CBank &,BBank &,GBank &); //声明Total函数为BBank类的友元函数
private:
char id[];
char key[];
double balance;
}; BBank::BBank(char Id[],char Key[],double Balance) //构造函数原型声明
{
for(int i=;i<;i++)
id[i]=Id[i];
for(int j=;j<;j++)
key[j]=Key[j];
balance=Balance;
} class GBank //GBank类的声明
{public:
GBank(char*,char*,double);
friend void Total(CBank &,BBank &,GBank &); //声明Total函数为GBank类的友元函数
private:
char id[];
char key[];
double balance;
}; GBank::GBank(char Id[],char Key[],double Balance) //构造函数原型声明
{
for(int i=;i<;i++)
id[i]=Id[i];
for(int j=;j<;j++)
key[j]=Key[j];
balance=Balance;
} void Total(CBank &c,BBank &b,GBank &g) //友元函数,c、b、g分别为CBank、BBank、GBank类对象的引用
{
int s=;
for(int i=;i<;i++)
{
if(c.id[i]==b.id[i] && c.id[i]==g.id[i] && b.id[i]==g.id[i])
{
for(int j=;j<;j++)
{
if(c.key[j]==b.key[j] && c.key[j]==g.key[j] && b.key[j]==g.key[j])
{
s=; //完全正确,结果s赋值为1
continue; //继续循环判断
}
else
{
s=; //账户号码正确 ,但密码错误,结果赋值为2
break; //跳出循环判断
}
}
}
else
{
s=; //账号信息完全不符,结果赋值为3
break; //跳出循环判断
}
} switch(s) //判断结果类型
{
case :
cout<<"总存款为:"<<endl;
cout<<c.balance<<"+"<<b.balance<<"+"<<g.balance<<"="<<c.balance+b.balance+g.balance<<"元"<<endl;
break;
case :
cout<<"账号密码错误!"<<endl;
break;
case :
cout<<"账号名称不符!"<<endl;
break;
default:
cout<<"发生未知错误,请联系银行客服!"<<endl;
break;
}
} int main()
{
CBank c("张三","",);
BBank b("张三","",);
GBank g("张三","",);
Total(c,b,g); getchar(); getchar();
return ;
}

运行结果:

编写程序时遇到的一些问题及解决思路历程:

关于循环判断的问题:一开始我的Total函数是这样写的:

 void Total(CBank &c,BBank &b,GBank &g)
{
for(int i=;i<;i++)
{
if(c.id[i]==b.id[i] && c.id[i]==g.id[i] && b.id[i]==g.id[i])
{
for(int j=;j<;j++)
{
if(c.key[j]==b.key[j] && c.key[j]==g.key[j] && b.key[j]==g.key[j])
{
cout<<"总存款为:"<<endl;
cout<<c.balance<<"+"<<b.balance<<"+"<<g.balance<<"="<<c.balance+b.balance+g.balance<<"元"<<endl;
}
else
cout<<"账号密码错误!"<<endl;
}
}
else
cout<<"账号信息不符!"<<endl;
}
}

运行结果:

和预期的不同,出现了30次结果。回到代码,发现好像也解释得通:要判断Id和Key数组中每个元素的情况,必然用到循环语句;可只要第i个元素相同,满足条件,就会执行cout输出操作。

请教了老师,他建议我自定义一个布尔函数进行判断,若循环内能满足所有判断条件,则返回true,否则返回false。我自定义了一个Verify函数,代码如下:

bool Verify(char a[],b[])
{
for(int i=;i<;i++)
{
if(c.id[i]==b.id[i] && c.id[i]==g.id[i] && b.id[i]==g.id[i])
{
for(int j=;j<;j++)
{
if(c.key[j]==b.key[j] && c.key[j]==g.key[j] && b.key[j]==g.key[j])
return true;
}
else
return false;
}
} int main()
{
CBank c("张三","",);
BBank b("张三","",);
GBank g("张三","",);
if(Verify(Id[],Key[]))
{
cout<<"总存款为:"<<endl;
cout<<c.balance<<"+"<<b.balance<<"+"<<g.balance<<"="<<c.balance+b.balance+g.balance<<"元"<<endl;
}
else cout<<"账号信息错误!"<<endl; return ;
getchar(); getchar();
}

发现又出现了新的问题:

一、  Id和Key都是类的私有成员,Verify函数无法访问它们。

二、  Verify函数是在main主函数中运行的,但该函数判断完后还有输出语句需访问类的私有成员。

三、  bool函数结果只有两种结果,无法反映多结果的情况。

问题一的解决思路:

1. 将Verify函数定义为类的友元函数。

2.将Verify的参数改成6个字符串类型,对应3个银行的Id和Key数组。

问题二的解决思路:自定义一个输出函数,它是三个类的公共友元函数。

问题三的解决思路:不使用bool型,而改用switch语句判断。

综合三个问题的思路,得出两个解决办法:

方法一:

自定义bool型判断函数和void型输出函数,他们都是三个类的友元函数,都能访问三个类的私有成员。void型输出函数根据bool型判断函数的返回值输出不同结果。

方法二:

在原Total函数中,利用bool型返回值判断的思路,定义一个变量s作为返回值。根据循环判断结果赋给s不同的值,再根据s的值输出不同的结果。开头给出的函数就是使用了法二。

总结:

两种方法都可行,两者的时间复杂度相同。但法一较法二不能做到解决问题三的优化,因此法二有更大的可拓展性和适应性。

《C++面向对象程序设计》第6章课后编程题2拓展的更多相关文章

  1. 面向对象程序设计--Java语言第二周编程题:有秒计时的数字时钟

    有秒计时的数字时钟 题目内容: 这一周的编程题是需要你在课程所给的时钟程序的基础上修改而成.但是我们并不直接给你时钟程序的代码,请根据视频自己输入时钟程序的Display和Clock类的代码,然后来做 ...

  2. c++面向对象程序设计第四章课后习题

    这是书上的习题,我使用的是VS2010运行编译的 原习题: 4.有两个矩阵a和b,均为两行三列.求两个矩阵之和.重载运算符“+”,使之能用于矩阵相加.如c=a+b. #include<iostr ...

  3. 面向对象程序设计--Java语言第一周编程题:分数

    分数 题目内容: 设计一个表示分数的类Fraction.这个类用两个int类型的变量分别表示分子和分母. 这个类的构造函数是: Fraction(int a, int b) 构造一个a/b的分数. 这 ...

  4. 已看1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架、多线程(并发编程)、I/O(NIO)、Socket、JDBC、XML、反射等。[泛型]\

    1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架.多线程(并发编程).I/O(NIO).Socket.JDBC.XML.反射等.[泛型]\1* ...

  5. Java面向对象程序设计第14章3-8和第15章6

    Java面向对象程序设计第14章3-8和第15章6 3.完成下面方法中的代码,要求建立一个缓冲区,将字节输入流中的内容转为字符串. import java.io.*; public class tes ...

  6. Java面向对象程序设计第9章1-9

    Java面向对象程序设计第9章1-9 1. 线程和进程的联系和区别是什么? 联系: 一个进程可以包括多个线程. 区别: 进程: 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统 ...

  7. Java面向对象程序设计第8章3-5

    Java面向对象程序设计第8章3-5 3.String类型有什么特点? 一旦赋值,便不能更改其指向的字符对象 如果更改,则会指向一个新的字符对象 不能为null 4.String什么时候进行值比较,什 ...

  8. Java面向对象程序设计第7章1-8

    Java面向对象程序设计第7章1-8 1."程序中凡是可能出现异常的地方必须进行捕获或拋出",这句话对吗? 不对. 异常分两类,runtime异常和非runtime异常. runt ...

  9. Java面向对象程序设计第5章1-9

    1.面向对象的主要特征是什么? 三大特征是:封装.继承和多态. 封装:是指将某事物的属性和行为包装到对象中,这个对象只对外公布需要公开的属性和行为,而这个公布也是可以有选择性的公布给其它对象. 继承: ...

随机推荐

  1. [Effective Java 读书笔记] 第二章 创建和销毁对象 第五条

    第五条 避免创建不必要的对象 书中一开始举例: String s = new String("stringette"); // don't do this //应该使用下面,只会创 ...

  2. javascript 防止多次提交或执行(在规定时间段内只允许执行一次) 默认 3000ms

    "use strict" class Func{ constructor(){} isRun(id, time){//防止多次提交或执行(在规定时间段内只允许执行一次) 默认 30 ...

  3. pt-query-digest 慢日志监控

    一.安装percona-toolkit,以centos为例 yum -y install https://repo.percona.com/yum/percona-release-latest.noa ...

  4. 2.【Spring Cloud Alibaba】实现负载均衡-Ribbon

    负载均衡的两种方式 如何实现负载均衡 目前已经实现让A总能找到B,如何实现负载均衡 负载均衡的两种方式 服务器端负载均衡 客户端负载均衡 使用Ribbo实现负载均衡 Ribbon是什么 ==Netfl ...

  5. springboot 基于Tomcate的自启动流程

    Springboot 内置了Tomcat的容器,我们今天来说一下Springboot的自启动流程. 一.Spring通过注解导入Bean大体可分为四种方式,我们主要来说以下Import的两种实现方法: ...

  6. light oj1170 - Counting Perfect BST卡特兰数

    1170 - Counting Perfect BST BST is the acronym for Binary Search Tree. A BST is a tree data structur ...

  7. 解决pycharm打开html页面一直刷新

    顺序——> File ——>Project:项目名——>project Structure 右侧的 + Add ContentRoot下面只保留本项目路径,其他全删了 方法2(推荐) ...

  8. linux--解决celery消息中间件带来的一系列问题

    启动celery定时任务 1.celery -A OpsManage beat -l info -S django 2.celery -A OpsManage worker -l info 此时消息中 ...

  9. C#设计模式学习笔记:(11)享元模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7792973.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲结构型设计模式的第六个模式--享 ...

  10. RequestFacade对象获取请求头时忽略大小写

    也许在Controller层 在RequestFacde文件中getHeader函数逻辑实现如下所示: public String getHeader(String name) { if(this.r ...