银行系统简答题
1
- bin文件夹 存放可执行文件
2
年利的理解
由于账户的余额是不断变化的,因此:年利 = 日均余额 * 年利率
日均余额 = 一年当中每天的余额累计起来/一年的总天数
accumulate
方法accumulate
方法用于计算从上次记录到当前日期期间的累计金额。accumulation
是之前的累积值。balance * (date - lastDate)
计算的是从lastDate
到date
期间的余额累积值。- 返回的值表示到当前日期为止的总累积金额。
sellte
方法settle
方法用于结算利息,通常在年末或季度末调用。accumulate(date)
计算到当前日期为止的累积金额。interest = accumulate(date) * rate / 365
计算利息,假设年利率是rate
,这里的除以 365 是为了将年利率转换为日利率。- 如果计算的利息不为零,则调用
record(date, interest)
将利息记录到账户。 - 最后将
accumulation
重置为 0,因为利息已经结算,重新开始新的积累周期。
3
静态成员可以在所有类实例之间共享数据
在整个应用程序中需要一个共同的状态或值的时候需要用到静态成员
代码中在SavingsAccount
类中,使用了静态成员 total
。
total
这个静态成员记录了所有 SavingsAccount
实例的总余额。
- 声明和初始化:
private:
static double total;
这里,total
被声明为类的私有静态成员,这意味着它只能被类的成员函数访问,不能直接从类外部访问。
double SavingsAccount::total = 0;
这一行初始化了静态成员 total
。静态成员需要在类定义外进行定义。
- 成员函数中的修改:
record
函数负责更新总余额total
。
每当存款或取款被记录时,total
余额相应更新。这确保了 total
始终反映所有 SavingsAccount
实例的余额总和。
- 访问静态成员: 静态成员
total
可以通过静态成员函数访问:
static double getTotal() { return total; };
这个函数允许外部代码在不需要 SavingsAccount
实例的情况下获取 total
的值。
4
在日期初始化时预先计算每个日期的总天数
再通过简单的减法得到两个日期相距的天数
5
SavingAccount类
CreditAccount类
它们都继承自Account
类,并实现了共同的存款、取款、结算利息和显示信息的方法。
这些共性体现在:
-
继承关系:
- 两个类都继承自
Account
类,利用了Account
类的基本账户功能。
- 两个类都继承自
-
构造函数:
- 两个类的构造函数都调用了
Account
类的构造函数来初始化账户的基本信息(如创建日期和账户ID)。 - 同时,它们都在构造函数中初始化了一个
acc
对象用于记录账户变动。
- 两个类的构造函数都调用了
-
存款和取款操作(
deposit
和withdraw
方法):- 用于向账户中存取钱。存取款操作会调用
record
方法记录存取款操作,并更新acc
对象的余额。
- 用于向账户中存取钱。存取款操作会调用
-
结算利息操作(
settle
方法):- 两个类都有
settle
方法用于结算利息。 - 它们都调用
acc
对象的change
方法来更新账户余额,并根据一定的利率计算利息。
- 两个类都有
-
显示信息(
show
方法):- 两个类都有
show
方法用于展示账户的当前状态,包括账户ID、余额等信息。
- 两个类都有
-
私有成员变量:
- 两个类都有一个
acc
对象用于记录账户变动情况。 - 两个类都有一个用于存储利息的变量(虽然命名可能不同)。
- 两个类都有一个
-
公有成员变量:
CreditAccount
和SavingAccount
类都有一个rate
变量,用于存储利率信息(虽然使用场景不同,CreditAccount
是日利率,SavingAccount
是年利率)。
6
Accumulator类的作用
- 追踪账户余额变化: 记录每次余额变化的时间和金额。
- 计算累计金额: 在时间段内累积余额的变化,用于利息计算等。
- 重置累计值: 在结算后重置累计值,以便下一次计算。
使用Accumulator类的函数举例
在CreditAccount
和SavingsAccount
类中,Accumulator
类被用来记录和计算账户的累计金额。以下是三个具体的例子:
-
存款操作(
deposit
方法)在
CreditAccount
和SavingsAccount
的deposit
方法中,存款操作会调用acc.change(date, getBalance())
来更新累积金额。 -
取款操作(
withdraw
方法)在
CreditAccount
和SavingsAccount
的withdraw
方法中,取款操作也会调用acc.change(date, getBalance())
来更新累积金额。 -
结算操作(
settle
方法)
在CreditAccount
和SavingsAccount
的settle
方法中,结算利息时会先调用acc.change(date, 0)
来更新累计金额,然后使用累积的金额来计算利息,并在结算后重置累计值。
7
在 CreditAccount
类中,以下函数没有被定义成虚函数:
CreditAccount(Date date, string id, double credite, double rate, double fee)
double get_debt() const
double get_credit() const
double get_rate() const
double get_fee() const
原因
-
构造函数
CreditAccount(Date date, string id, double credite, double rate, double fee)
- 构造函数不能是虚函数。虚函数的主要目的是实现多态性,而构造函数的作用是初始化对象。在对象创建的过程中,还没有具体的对象实例,所以无法进行多态调用。
-
Getter 函数
double get_debt() const
double get_credit() const
double get_rate() const
double get_fee() const
- Getter 函数通常是小的、内联的函数,它们直接返回类成员变量的值。在设计上,getter 函数通常不需要多态性。它们的实现通常是固定的,不需要在子类中被重写。
- 这些函数是对私有成员变量的简单访问,不涉及到复杂的行为变化,因此不需要虚函数机制。
8
因为两个派生类的settle函数的实现存在着差异:
-
储蓄账户一年结算一次,SavingAccount类的settle函数需要对每年1月1日调用。
-
信用卡账户一月结算一次,CreditAccount类的settle函数需要对每月1月1日调用
但是使用基类Account指针来调用settle函数时,事先并不知道该指针所指向对象的具体类型,无法决定采用何种方式调用settle函数
所以只能将二者统一为对每月1日的调用。
SavingsAccount
-
条件检查
- 检查是否是1月。如果是1月,则进行结算操作。
-
更新累积器
acc.change(date, 0)
将累积器的状态更新到当前日期。
-
计算利息
- 利用累积的金额和利率来计算年利息。
acc.getSum(date)
获取累积的金额。 - 利用年利率
rate
和过去一年中的天数来计算利息。
- 利用累积的金额和利率来计算年利息。
-
记录利息
record(date, interest, "interest")
将利息记录到账户中。
CreditAccount
-
更新累积器:
acc.change(date, getBalance())
将累积器的状态更新到当前余额和日期。
-
计算利息:
- 利用累积的金额和日利率来计算利息。
acc.getSum(date)
获取累积的金额。 - 直接用累积金额乘以日利率
rate
来计算利息。
- 利用累积的金额和日利率来计算利息。
-
记录利息和年费:
- 如果日期是1月1日,则记录利息并扣除年费。
- 否则,只记录利息。
-
重置累积器:
interest = 0
清除利息。acc.reset(date, getBalance())
重置累积器为当前日期和余额。
9
vector
和普通数组的区别
-
动态大小
-
- vector:
vector
是一个动态数组,可以自动调整大小。在代码中,vector accounts;
定义了一个vector
,其初始大小为 0,但可以根据需要增加或减少元素。
- vector:
-
- 普通数组:大小是固定的。例如,
Account* accounts[10];
声明了一个大小为 10 的数组,不能再增加或减少元素。
- 普通数组:大小是固定的。例如,
-
内存管理:
- vector:
vector
自动管理内存。添加元素时,vector
会自动分配更多的内存。在代码中,accounts.push_back(account);
自动处理内存分配。 - 普通数组:需要手动管理内存。对于动态数组,需要使用
new
和delete
。例如,Account* accounts = new Account[10];
并在不需要时手动delete[] accounts;
。
- vector:
-
元素插入和删除:
-
- vector:
vector
提供方便的插入和删除方法。在代码中,accounts.push_back(account);
用于在末尾添加元素,而for_each(accounts.begin(), accounts.end(), deleter());
用于删除所有元素。
- vector:
-
- 普通数组:固定大小数组无法插入或删除元素,只能修改已有元素。动态数组需要手动管理大小变化,操作复杂且容易出错。
-
安全性和便捷性:
- vector:
vector
提供了很多成员函数,如push_back
、pop_back
、begin
、end
等,方便进行各种操作,并且具有边界检查功能,安全性高。 - 普通数组:操作简单但功能有限,没有边界检查等安全机制。
- vector:
10
query()
函数的实现
-
使用
lower_bound
找到开始日期lower_bound(date1)
返回一个迭代器,指向第一个不小于date1
的元素。
-
使用
upper_bound
找到结束日期upper_bound(date2)
返回一个迭代器,指向第一个大于date2
的元素。
-
遍历查询结果
- 从开始迭代器遍历到结束迭代器,并调用每个记录的
show()
方法显示记录内容。
- 从开始迭代器遍历到结束迭代器,并调用每个记录的
11
举例
12
-
读取用户输入的命令:
cin >> cmd;
-
处理不同的命令:
根据命令种类判断是否需要存入 command.txt
中
-
- 需要存入
-
添加账户 ('a'):
-
- 需要存入
-
-
-
-
读取账户类型和ID
-
检查账户类型是否有效
- 如果账户类型是 's'(储蓄账户)或 'c'(信用账户),则将命令、账户类型和ID写入文件
commands.txt
。 - 如果账户类型无效,输出错误信息并跳出当前命令处理。
- 如果账户类型是 's'(储蓄账户)或 'c'(信用账户),则将命令、账户类型和ID写入文件
-
根据账户类型读取相关信息并创建账户对象
-
-
-
-
-
-
存款 ('d'):
-
-
-
-
-
- 读取账户索引、存款金额以及描述信息
- 检查账户索引是否合法
- 不合法,输出错误信息并跳出命令处理。
- 合法,则对指定账户执行存款操作。
- 将存款操作的命令和参数写入文件
commands.txt
中
-
-
-
-
-
取款 ('w'):
-
-
-
-
-
改变日期 ('c'):
-
-
-
-
-
- 首先读取新的日期天数部分
- 检查新的天数是否早于当前天数,如果是,输出错误信息并退出命令处理
- 检查新的天数是否超过当前月份的最大天数,如果是,输出错误信息并退出命令处理
- 如果新的天数有效,更新当前日期并将该命令记录到文件
commands.txt
中
-
-
-
-
-
进入下个月 ('n'):
-
-
-
-
-
- 首先检查当前月份,如果是12月则更新日期到下一年的1月1日,否则更新到下个月的1日
- 对所有账户调用
settle
方法进行结算操作 - 将命令记录到文件
commands.txt
中
-
-
-
- 不需要存入
- 显示账户信息 ('s'):
- 不需要存入
-
-
-
查询账目 ('q'):
-
-
-
-
-
退出 ('e'):
-
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)