银行系统简答题

1

文件结构分为五部分
  • .vscode文件夹 存放配置文件
  • build文件夹 存放中间生成的静态库、临时文件、可执行文件等,可直接删除,避免了对源程序的污染。
    • bin文件夹 存放可执行文件
  • include文件夹 存放.h头文件
  • src文件 存放.cpp源程序
  • 最后为主程序 main.cpp以及对应的cmakelists.txt文件
  •  

    2

    年利的理解

    由于账户的余额是不断变化的,因此:年利 = 日均余额 * 年利率 

    日均余额 = 一年当中每天的余额累计起来/一年的总天数

    • accumulate 方法
      • accumulate 方法用于计算从上次记录到当前日期期间的累计金额。
      • accumulation 是之前的累积值。
      • balance * (date - lastDate) 计算的是从 lastDatedate 期间的余额累积值。
      • 返回的值表示到当前日期为止的总累积金额。

     

    • 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类,并实现了共同的存款、取款、结算利息和显示信息的方法。

    这些共性体现在:

    1. 继承关系:

      • 两个类都继承自Account类,利用了Account类的基本账户功能。
    2. 构造函数:

      • 两个类的构造函数都调用了Account类的构造函数来初始化账户的基本信息(如创建日期和账户ID)。
      • 同时,它们都在构造函数中初始化了一个acc对象用于记录账户变动。
    3. 存款和取款操作(depositwithdraw方法):

      • 用于向账户中存取钱。存取款操作会调用record方法记录存取款操作,并更新acc对象的余额。
    4. 结算利息操作(settle方法):

      • 两个类都有settle方法用于结算利息。
      • 它们都调用acc对象的change方法来更新账户余额,并根据一定的利率计算利息。
    5. 显示信息(show方法):

      • 两个类都有show方法用于展示账户的当前状态,包括账户ID、余额等信息。
    6. 私有成员变量:

      • 两个类都有一个acc对象用于记录账户变动情况。
      • 两个类都有一个用于存储利息的变量(虽然命名可能不同)。
    7. 公有成员变量:

      • CreditAccountSavingAccount类都有一个rate变量,用于存储利率信息(虽然使用场景不同,CreditAccount是日利率,SavingAccount是年利率)。

    6

    Accumulator类的作用

    1. 追踪账户余额变化: 记录每次余额变化的时间和金额。
    2. 计算累计金额: 在时间段内累积余额的变化,用于利息计算等。
    3. 重置累计值: 在结算后重置累计值,以便下一次计算。

    使用Accumulator类的函数举例

    CreditAccountSavingsAccount类中,Accumulator类被用来记录和计算账户的累计金额。以下是三个具体的例子:

    1. 存款操作(deposit方法)

      CreditAccountSavingsAccountdeposit方法中,存款操作会调用acc.change(date, getBalance())来更新累积金额。

    2. 取款操作(withdraw方法)

      CreditAccountSavingsAccountwithdraw方法中,取款操作也会调用acc.change(date, getBalance())来更新累积金额。

    3. 结算操作(settle方法)

    CreditAccountSavingsAccountsettle方法中,结算利息时会先调用acc.change(date, 0)来更新累计金额,然后使用累积的金额来计算利息,并在结算后重置累计值。

    7

    CreditAccount 类中,以下函数没有被定义成虚函数:

    1. CreditAccount(Date date, string id, double credite, double rate, double fee)
    2. double get_debt() const
    3. double get_credit() const
    4. double get_rate() const
    5. double get_fee() const

    原因

    1. 构造函数

      • CreditAccount(Date date, string id, double credite, double rate, double fee)
        • 构造函数不能是虚函数。虚函数的主要目的是实现多态性,而构造函数的作用是初始化对象。在对象创建的过程中,还没有具体的对象实例,所以无法进行多态调用。
    2. 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 和普通数组的区别

    1. 动态大小

      • vectorvector 是一个动态数组,可以自动调整大小。在代码中,vector accounts; 定义了一个 vector,其初始大小为 0,但可以根据需要增加或减少元素。
      • 普通数组:大小是固定的。例如,Account* accounts[10]; 声明了一个大小为 10 的数组,不能再增加或减少元素。
    1. 内存管理

      • vectorvector 自动管理内存。添加元素时,vector 会自动分配更多的内存。在代码中,accounts.push_back(account); 自动处理内存分配。
      • 普通数组:需要手动管理内存。对于动态数组,需要使用 newdelete。例如,Account* accounts = new Account[10]; 并在不需要时手动 delete[] accounts;
    2. 元素插入和删除

      • vectorvector 提供方便的插入和删除方法。在代码中,accounts.push_back(account); 用于在末尾添加元素,而 for_each(accounts.begin(), accounts.end(), deleter()); 用于删除所有元素。
      • 普通数组:固定大小数组无法插入或删除元素,只能修改已有元素。动态数组需要手动管理大小变化,操作复杂且容易出错。
    1. 安全性和便捷性

      • vectorvector 提供了很多成员函数,如 push_backpop_backbeginend 等,方便进行各种操作,并且具有边界检查功能,安全性高。
      • 普通数组:操作简单但功能有限,没有边界检查等安全机制。

    10

    query() 函数的实现

    1. 使用 lower_bound 找到开始日期

      • lower_bound(date1) 返回一个迭代器,指向第一个不小于 date1 的元素。
    2. 使用 upper_bound 找到结束日期

      • upper_bound(date2) 返回一个迭代器,指向第一个大于 date2 的元素。
    3. 遍历查询结果

      • 从开始迭代器遍历到结束迭代器,并调用每个记录的 show() 方法显示记录内容。

    11

    我编写了read_cmd()函数用于处理command.txt文件中的每一条命令。
     
    read_cmd()函数
    • ifstream的对象 ifs 打开了"commands.txt"文件
    • 然后使用了流提取运算符>>来读取每一条命令中的各个部分

    举例

      1. ifs >> cmd读取了一个字符到变量cmd
      2. 根据cmd的值,ifs >> type >> id首先从文件中读取一个字符并将其保存到type
      3. 然后跳过任何的空白字符(包括空格、换行符等),再读取下一个字符串到id
      4. 之后的流提取运算符ifs >> rate的工作方式相同,它会跳过空格并读取一个浮点数到rate
      5. 最后得到
        • type = "s"
        • id = "S3755217"
        • rate = 0.015
     

    12

    1. 读取用户输入的命令:

    cin >> cmd;

    1. 处理不同的命令:

    根据命令种类判断是否需要存入 command.txt 中

      • 需要存入
        • 添加账户 ('a'):

          1. 读取账户类型和ID

          2. 检查账户类型是否有效

            • 如果账户类型是 's'(储蓄账户)或 'c'(信用账户),则将命令、账户类型和ID写入文件 commands.txt
            • 如果账户类型无效,输出错误信息并跳出当前命令处理。
          3. 根据账户类型读取相关信息并创建账户对象

        • 存款 ('d'):

          1. 读取账户索引、存款金额以及描述信息
          2. 检查账户索引是否合法
            • 不合法,输出错误信息并跳出命令处理。
            • 合法,则对指定账户执行存款操作。
          3. 将存款操作的命令和参数写入文件 commands.txt
        • 取款 ('w'):

        • 改变日期 ('c'):

          1. 首先读取新的日期天数部分
          2. 检查新的天数是否早于当前天数,如果是,输出错误信息并退出命令处理
          3. 检查新的天数是否超过当前月份的最大天数,如果是,输出错误信息并退出命令处理
          4. 如果新的天数有效,更新当前日期并将该命令记录到文件 commands.txt
        • 进入下个月 ('n'):

          1. 首先检查当前月份,如果是12月则更新日期到下一年的1月1日,否则更新到下个月的1日
          2. 对所有账户调用 settle 方法进行结算操作
          3. 将命令记录到文件 commands.txt
      • 不需要存入
        • 显示账户信息 ('s'):

        • 查询账目 ('q'):

        • 退出 ('e'):

     

    posted @   study_all_day  阅读(35)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 全程不用写代码,我用AI程序员写了一个飞机大战
    · DeepSeek 开源周回顾「GitHub 热点速览」
    · 记一次.NET内存居高不下排查解决与启示
    · MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
    · .NET10 - 预览版1新功能体验(一)
    点击右上角即可分享
    微信分享提示