设计一个程序,其中有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. To be contine ,NW NMM backup sqlserver failed.

    Last time, we talk about separate under one cluster backup into two diffetent AG backup. Does it wor ...

  2. The Divide and Conquer Approach - 归并排序

    The divide and conquer approach - 归并排序 归并排序所应用的理论思想叫做分治法. 分治法的思想是: 将问题分解为若干个规模较小,并且类似于原问题的子问题, 然后递归( ...

  3. JDK14都要问世了,你还在用JDK8吗

    Java开发工具包(JDK)14已进入发布候选阶段,总体功能基本已确定.计划中的标准Java升级将具有新功能,例如JDK Flight Recorder事件流,模式匹配和开关表达式. JDK 14计划 ...

  4. Hapi+MySql项目实战自动化文档生成(四)

    自动化生成swagger文档 使用hapi插件hapi-swagger,简单配置下插件,先修改下plugin_config.js文件: //plugin_config.js const Swagger ...

  5. 解决mysql登录报错ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)问题

    问题描述: 在ubuntu14.04上安装完MYSQL后,MYSQL默认给分配了一个默认密码,但当自己在终端上使用默认密码登录的时候,总会提示一个授权失败的错误. 报错信息:Access denied ...

  6. Linux安装virtualenvwrapper

    1.pip install virtualenvwrapper 2.export WORKON_HOME=/home/virtualenv  //配置虚拟环境变量,以后直接mkvirtualenv 虚 ...

  7. 零基础Python应该怎样学习呢?(附视频教程)

    Python应该怎样学习呢? 阶段一:适合自己的学习方式 对于零基础的初学者来说,最迷茫的是不知道怎样开始学习?那这里小编建议可以采用视频+书籍的方式进行学习.看视频学习可以让你迅速掌握编程的基础语法 ...

  8. 06.JS对象-1

    前言: 学习一门编程语言的基本步骤(01)了解背景知识(02)搭建开发环境(03)语法规范(04)常量和变量(05)数据类型(06)数据类型转换(07)运算符(08)逻辑结构(09)函数(10)对象1 ...

  9. iOS开发 - 在SwiftUI中显示模态视图

    在SwiftUI中显示模态视图 简介 这里教大家如何弹出一个简单的模态视图.分别有两个页面,ContentView和GCPresentedView,以下对应简称为A和B.我们要做的是在A视图中点击按钮 ...

  10. ES相关知识

    ElkStack介绍 对于日志来说,最常见的需求就是收集.存储.查询.展示,开源社区正好有相对应的开源项目:logstash(收集).elasticsearch(存储+搜索).kibana(展示),我 ...