提问者:小点点

无法实例化抽象类,但双重检查了虚函数的重写


我在自学C++。我试过书中的一个程序,它通常会使用指针数组动态分配两个派生类的几个对象。然而,我正在准备一个不允许我使用指针的作业,所以我做了一个没有指针的替代版本。

它给我的唯一错误是C2259“不能实例化抽象类”,但我很确定我已经覆盖了所有的虚函数。

下面是标题:

#ifndef ACCTBAC_H_
#define ACCTBAC_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
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() {}
};

// Brass Plus 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.1);
    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

类函数:

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

// Abstract Base Class
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;
}

// protected methods for formatting
AcctABC::Formatting AcctABC::SetFormat() const
{
    // set up ###.## format
    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);
}

// Brass methods
void Brass::Withdraw(double amt)
{
    if (amt < 0)
        cout << "Withdrawal amount must be positive; "
        << "withdrawal cancelled.\n";
    else if (amt <= Balance())
        AcctABC::Withdraw(amt);
    else
        cout << "Withdrawal amount of $" << amt
        << " exceeds your balance.\n"
        << "Withdrawal cancelled.\n";
}

void Brass::ViewAcct() const
{
    Formatting f = SetFormat();

    cout << "Brass Client: " << FullName() << "\n";
    cout << "Account Number: " << AcctNum() << "\n";
    cout << "Balance: $" << Balance() << "\n";
    Restore(f);
}

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

void BrassPlus::ViewAcct() const
{
    Formatting f = SetFormat();

    cout << "BrassPlus Client: " << FullName() << "\n";
    cout << "Account Number: " << AcctNum() << "\n";
    cout << "Balance: $" << Balance() << "\n";
    cout << "Maximum loan: $" << maxLoan << "\n";
    cout << "Owed to bank: $" << owesBank << "\n";
    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 << "\n";
        cout << "Finance charge: $" << advance * rate << "\n";
        Deposit(advance);
        AcctABC::Withdraw(amt);
    }
    else
        cout << "Credit limit exceeded. Transaction cancelled.\n";
    Restore(f);
}

和主程序:

// usebrass3.cpp -- polymorphic example using an abstract base class
#include <iostream>
#include <string>
#include "acctabc.h"
#include <vector>
const int CLIENTS = 4;

int main()
{
    using std::cin;
    using std::cout;
    using std::vector;
    using std::string;

    vector<AcctABC> accounts(CLIENTS);
    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: ";
        while (cin >> kind && (kind != '1' && kind != '2'))
            cout << "Enter either 1 or 2: ";
        if (kind == 1)
            accounts.push_back(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;
            accounts.push_back(BrassPlus(temp, tempnum, tempbal, tmax, trate));
        }
        while (cin.get() != '\n')
            continue;
    }
    cout << "\n";
    for (int i = 0; i < CLIENTS; i++)
    {
        accounts[i].ViewAcct();
        cout << "\n";
    }
    cout << "Done.\n";

    return 0;
}

共2个答案

匿名用户

你不能这样做

vector<AcctABC> accounts(CLIENTS);

因为它将使默认构造的抽象基类数。您还将失去多态性并导致对象切片。取而代之的是

vector<std::unique_ptr<AcctABC>> accounts;

然后例如

accounts.push_back(std::make_unique<Brass>(temp, tempnum, tempbal));

匿名用户

此处:

vector<AcctABC> accounts(CLIENTS);

您正在尝试使用默认构造的元素创建向量。但是当类是抽象类时,不能有元素。在元素。当您想在向量中存储多态类型时,需要指针。