C++PrimerPlus:第十三章类和继承:应用ABC概念

第十三章类和继承:引用ABC概念

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第十三章类和继承:应用ABC概念


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

第十三章类和继承:应用ABC概念


提示:以下是本篇文章正文内容,下面案例可供参考

一、应用ABC概念

您可能希望看到一个完整的 ABC示例,因此这里将这一概念用于 Brass 和 BrassPlus 账户,首先定义一个名为AcCtABC的ABC。这个类包含Brass和BrassPlus类共有的所有方法和数据成员,而那些在BrassPlus 类和 Brass 类中的行为不同的方法应被声明为虚函数。至少应有一个虚函数是纯虚函数,这样才能使 AcctABC 成为抽象类。
程序清单13.11的头文件声明了AcctABC类(ABC)、Brass类和 BrassPlus类(两者都是具体类)。为帮助派生类访问基类数据,AcctABC提供了一些保护方法;派生类方法可以调用这些方法,但它们并不是派生类对象的公有接口的组成部分。AcctABC还提供一个保护成员函数,用于处理格式化(以前是使用非成员函数处理的)。另外,AcctABC类还有两个纯虚函数,所以它确实是抽象类。

一,程序清单 13.11acctabc.h

//acctabc.h -- bank account classes
#ifndef ACCTABC_H_
#define ACCTABC_H_
#include <iostream>
#include <string>

// Abstract base class
class AcctABC
{
private:
    std::string fullName;
    long acctNum;
    double balance;
protected:
    struct Formatting
    {
        std::ios_base::fmtflags flag;
        std::streamsize pr;
    };
    const std::string& FullName() const { return fullName; }
    long AcctNum() const { return acctNum; }
    Formatting SetFormat() const;
    void Restore(Formatting& f) const;
public:
    AcctABC(const std::string& s = "Nullbody", long an = -1,
        double bal = 0.0);
    void Deposit(double amt);
    virtual void Withdraw(double amt) = 0;//pure virtual function
    double Balance() const { return balance; }
    virtual void ViewAcct() const = 0;//pure virtual function
    virtual~AcctABC() {}
};
// Brass Account Class
// Normal account
class Brass : public AcctABC
{
public:
    Brass(const std::string& s = "Nullbody", long an = -1,
        double bal = 0.0) :AcctABC(s, an, bal) {};
    virtual void Withdraw(double amt);
    virtual void ViewAcct() const;
    virtual ~Brass() {};
};
// BrassPlus Account Class
class BrassPlus : public AcctABC
{
private:
    double maxLoan;
    double rate;
    double owesBank;
public:
    BrassPlus(const std::string& s = "Nullbody", long an = -1, 
        double bal = 0.0,double ml = 500, double r = 0.10);
    BrassPlus(const Brass& ba, double ml = 500, 
        double r = 0.10);
    virtual void ViewAcct() const;
    virtual void Withdraw(double amt);
    void ResetMax(double m) { maxLoan = m; }
    void ResetRate(double r) { rate = r; }
    void ResetOwes() { owesBank = 0; }
};
#endif 

接下来需要实现那些不是内联函数的方法,如程序清单13.12所示

二,程序清单 13.12 acctABC.cpp

// acctABC.cpp -- ABC account class methods
#include "acctABC.h"
#include <iostream>
using std::cout;
using std::ios_base;
using std::endl;
using std::string;

AcctABC::AcctABC(const string & s, long an, double bal)
{
    fullName = s;
    acctNum = an;
    balance = bal;
}

void AcctABC::Deposit(double amt)
{
    if (amt < 0)
        cout << "Negative deposit not allowed; "
             << "deposit is cancelled.\n";
    else
        balance += amt;
}
void AcctABC::Withdraw(double amt)
{
    balance -= amt;
}


AcctABC::Formatting AcctABC::SetFormat() const
{
    Formatting f;
    f.flag = cout.setf(ios_base::fixed, ios_base::floatfield);
    f.pr = cout.precision(2);
    return f;
}

void AcctABC::Restore(Formatting & f) const
{
    cout.setf(f.flag, ios_base::floatfield);
    cout.precision(f.pr);
}


void Brass::Withdraw(double amt)
{
    if (amt < 0)
        cout << "Negative withdrawal not allowed; "
             << "withdrawal cancelled.\n";
    else if (amt <= Balance())
        AcctABC::Withdraw(amt);
    else
        cout << "Withdrawal amount of $" << amt
             << " exceeds your balance.\n"
             << "Withdrawalcancelled.\n";
 }
void Brass::ViewAcct() const
{
    Formatting f = SetFormat();
    cout << "Brass Client: " << FullName() << endl;
    cout << "Account Number: " << AcctNum() << endl;
    cout << "Balance: $" << Balance() << endl;
    Restore(f);
}

BrassPlus::BrassPlus(const string & s, long an, double bal,
                     double ml, double r) : AcctABC(s, an, bal)
{
    maxLoan = ml;
    owesBank = 0.0;
    rate = r;
}

BrassPlus::BrassPlus(const Brass & ba, double ml, double r) : AcctABC(ba)
{
    maxLoan = ml;
    owesBank = 0.0;
    rate = r;
}

void BrassPlus::ViewAcct() const
{
    Formatting f = SetFormat();
    cout << "BrassPlus Client: " << FullName() << endl;
    cout << "Account Number: " << AcctNum() << endl;
    cout << "Balance: $" << Balance() << endl;
    cout << "Maximum loan: $" << maxLoan << endl;
    cout << "Owed to bank: $" <<owesBank << endl;   
    cout.precision(3);
    cout << "Loan Rate: " << 100 * rate << "%\n";
    Restore(f);
}

void BrassPlus::Withdraw(double amt)
{
    Formatting f = SetFormat();
    double bal = Balance();
    if (amt <= bal)
        AcctABC::Withdraw(amt);
    else if (amt <= bal + maxLoan - owesBank)
    {
        double advance = amt - bal;
        owesBank += advance * (1.0 + rate);
        cout << "Bank advance: $" << advance << endl;
        Deposit(advance);
        AcctABC::Withdraw(amt);
    }
    else
        cout << "Credit limit exceeded. Transaction cancelled.\n";
    Restore(f);
}



保护方法 FulIName()和 AcctNum()提供了对数据成员 fiullName 和 acctNum 的只读访问,使得可以进
一步定制每个派生类的 ViewAcct()。这个版本在设置输出格式方面做了两项改进。前一个版本使用两个函数调用来设置输出格式,并使用一个函数调用来恢复格式:

format initialState =setFormat();
precis prec =cout.precision(2)...
restore(initialState,prec);//restore original format

这个版本定义了一个结构,用于存储两项格式设置;并使用该结构来设置和恢复格式,因此只需两个函数调用:

struct Formatting
{
std::ios base::fmtfglas flag;
std::streamsize pr;
}
...
Formatting f=SetFormat();
...
Restore(f);

因此代码更整洁。
内此阳定盈。旧版本存在的问题是,setFormat()和restore()都是独立的函数,这些函数与客户定义的同名函数发生冲突。解决这种问题的方式有多种,一种方式是将这些函数声明为静态的,这样它们将归文件 brass.cpp及其继任 acctabc.cpp私有。另一种方式是,将这些函数以及结构 Formatting放在一个独立的名称空间中。但这个示例探讨的主题之一是保护访问权限,因此将这些结构和函数放在了类定义的保护部分。这使得它们对基类和派生类可用,同时向外隐藏了它们。

对于 Brass 和 BrassPlus账户的这种新实现,使用方式与旧实现相同,因为类方法的名称和接口都与以前一样。例如,为使程序清单13.10能够使用新的实现,需要采取下面的步骤将usebrass2.cpp 转换为usebrass3.cpp:

  • 使用 acctabc.cpp而不是brass.cpp来链接usebrass2.cpp。
  • 包含文件 acctabc.h,而不是 brass.h。
  • 将下面的代码:
Brass *p clients[CLIENTS];

替换为:

AcctABC *p clients[CLIENTS];

程序清单 13.13是修改后的文件,并将其重命名为usebrass3.cpp。
程序清单13.13 usebrass3.cpp

3,程序清单 13.13usebrass3.cpp


//usebrass3.cpp -- polymorphic example using an abstract base class 
//compile with acctacb.cpp

#if 1
#include <iostream>
#include "acctabc.h"
const int CLIENTS = 4;
int main()
{
    using std::cout;
    using std::endl;
    using std::cin;

    AcctABC* p_clients[CLIENTS];

    std::string temp;
    long tempnum;;
    double tempbal;
    char kind;

    for (int i = 0; i < CLIENTS; i++)
    {
        cout << "Enter client's name: ";
        getline(cin, temp);
        cout << "Enter client's account number: ";
        cin >> tempnum;
        cout << "Enter opening balance: $";
        cin >> tempbal;
        cout << "Enter 1 for Brass Account or "
             << "2 for BrassPlus Account:";
        while (cin >> kind && (kind != '1' && kind != '2'))
            cout << "Enter 1 or 2: ";
        if (kind == '1')
            p_clients[i] =new Brass(temp, tempnum, tempbal);
        else
        {
            double tmax, trate;
            cout << "Enter the overdraft limit: $";
            cin >> tmax;
            cout << "Enter the interest rate as a decimal fraction: ";
            cin >> trate;
            p_clients[i] = new BrassPlus(temp, tempnum, tempbal, tmax, trate);
        }
        while (cin.get() != '\n')
            continue;
    }

    cout << endl;
    for (int i = 0; i < CLIENTS; i++)
    {
        p_clients[i]->ViewAcct();
        cout << endl;
    }

    for (int i = 0; i < CLIENTS; i++)
        delete p_clients[i];

    cout<<"End of program."<<endl;
    return 0;

}
#endif // 0

该程序本身的行为与非抽象基类版本相同,因此如果输入与给程序清单13.10提供的输入相同,输出也将相同。

总结

提示:这里对文章进行总结:

暂无

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值