设计一个程序,其中有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. Java中类的关系

    在java里类的关系大致分为三种, 1.继承(a is b):继承extends,实现implement 2.包含(a has b):组合>聚合>关联.关系亲密度越来越小,一个类在另一个类 ...

  2. 【题解】P1559 运动员最佳匹配问题

    [题目](https://www.luogu.com.cn/problem/P1559) 题目描述 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组 ...

  3. 在Thinkphp3.1中使用Mongo的具体操作

    最近研究Mongo项目都是用TP开发的,先介绍下Mongo在TP3.1中的用法 首先要确保你的PHP环境中已经安装好Mongo扩展,在实际项目中大多数都是Mysql数据库为主的,那么如何添加一个Mon ...

  4. Golang内存模型

    Ref: https://golang.org/ref/mem 简介 golang内存模型,主要说明了如下问题.在一个goroutine中读取变量,而该变量是由其他goroutine赋值的,这种情况下 ...

  5. 构建ROP链实现远程栈溢出

    通常情况下栈溢出可能造成的后果有两种,一类是本地提权另一类则是远程执行任意命令,通常C/C++并没有提供智能化检查用户输入是否合法的功能,同时程序编写人员在编写代码时也很难始终检查栈是否会发生溢出,这 ...

  6. 本地开发环境伪装成SSL连接的实现

    本地ssl开发测试实现1,在外网服务器上使用测试域名和t.test.cn,用let's encrypt申请 证书并正常运行2,修改本地服务器host文件,将t.kennylee.vip指向127.0. ...

  7. Python - os.walk()详细使用

    os.walk() 方法简单介绍 主要用来遍历一个目录内各个子目录和子文件 是一个简单易用的文件.目录遍历器,可以帮助我们高效的处理文件.目录方面的事情. 方法参数介绍 os.walk(top[, t ...

  8. A water problem 大数取余。

    A water problem Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  9. 在debian10启动器中添加自定义应用

    首先要添加一个desktop类型的文件,搜索一下即可 若将desktop文件放在/usr/share/applicatios/中,需要执行update-desktop-database使新添加的应用生 ...

  10. C#设计模式学习笔记:(20)职责链模式

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