程序使用派生类的错误输出。不是为了心灵之光

时间:2011-04-24 20:25:30

标签: c++

注意:如果这个程序很难看,我很抱歉。这是我的第一个使用派生类的程序。我计划将其提交给代码审查后,我得到它做我想要的,所以我可以收到有关它如何设计得更好的提示。请随意在这里提供这些提示,但我对这篇文章的主要目的是让它正常工作。

该程序处理银行账户的提款和存款,然后应用利率。

问题:由于某种原因,在处理类类型“checkingAccount”的帐户时,似乎checkBalance的值被卡住并且在整个循环的其余部分都没有更新为新值。这很奇怪,因为相同的循环用于处理其他派生类“savingsAccount”,它工作正常,其中一个类型为“checkingAccount”的帐户似乎已经正确处理,所以我完全知道发生了什么。

如果有人可以帮助我解决这个问题,我将不胜感激。请不要犹豫,请我指明任何事情,我会尽快回复。

正在阅读的数据:

enter image description here

输出: enter image description here

我怀疑问题的代码是:

//This loop is exited early:

 for (int j = 0; j < transactionNum; j++)
            {
                inFile >> transactionTypeTemp >> amountTemp;
                inFile.get(discard);
                ba.applyTransaction(accountType, transactionTypeTemp, amountTemp, j);
            }

//when something in here occurs?
// c = j from loop

double checkingAccount:: applyTransaction(char transactionTypeTemp, int amountTemp, int c, double checkingBalance)
{
  if (transactionTypeTemp == 'D')
        {
            checkingBalance = checkingBalance + amountTemp;
        }
  else if (transactionTypeTemp == 'W')
        {
            if (checkingBalance < amountTemp)
            {
            cout << "error: transaction number " << c + 1 << " never occured due to insufficent funds." << endl;
            }
            else
            {
                checkingBalance = checkingBalance - amountTemp;
                if(checkingBalance < minimumBalance) //if last transaction brought the balance below minimum balance
                {
                    checkingBalance = (checkingBalance - serviceCharge); //apply service charge
                }
            }
        }

        return checkingBalance;
}

整个计划:

//header file
#include <iostream>
#include <fstream>


using namespace std;

class bankAccount
{
    public:
    bankAccount();
    void setAccountInfo(int accountNumTemp, double balanceTemp);
    void prePrint(char accountType);
    void applyTransaction(char accountType, char transactionTypeTemp, int amountTemp, int j);
    void applyInterest(char accountType);
    void postPrint();

    private:
    int accountNumber;
    double balance;
};

class checkingAccount: public bankAccount
{
    public:
    void prePrint(int accountNumber, char accountType, double checkingBalance);
    checkingAccount();
    double  applyTransaction(char transactionTypeTemp, int amountTemp, int c, double    checkingBalance);
    double  applyInterest(double checkingBalance);

    private:
    float interestRate;
    int minimumBalance;
    float serviceCharge;

};

class savingsAccount: public bankAccount
{
    public:
    void prePrint(int savingsAccountNumber, char accountType, double savingsBalance);
    savingsAccount();
    double applyTransaction(char transactionTypeTemp, int amountTemp, int c, double savingsBalance);
    double applyInterest(double checkingBalance);

    private:
    float interestRate;
};

//class implementation .cpp file

bankAccount:: bankAccount()
{
    accountNumber = 0;
    balance = 0;
}

void bankAccount:: setAccountInfo(int accountNumTemp, double balanceTemp)
{
    accountNumber = accountNumTemp;
    balance = balanceTemp;
}

void bankAccount:: prePrint(char accountType)
{
    if(accountType == 'C')
    {
        int checkingAccountNumber = accountNumber;
        double checkingBalance = balance;
        checkingAccount ca;
        ca.prePrint(checkingAccountNumber, accountType, checkingBalance);
    }
    else if (accountType == 'S')
    {
        int savingsAccountNumber = accountNumber;
        double savingsBalance = balance;
        savingsAccount sa;
        sa.prePrint(savingsAccountNumber, accountType, savingsBalance);
    }


}

void bankAccount:: applyTransaction(char accountType, char transactionTypeTemp, int amountTemp, int j)
{
    int c;
    c = j;
    double checkingBalance, savingsBalance;
    checkingAccount ca;
    savingsAccount sa;

        if (accountType == 'C')
        {
            checkingBalance = balance;
            balance = ca.applyTransaction(transactionTypeTemp, amountTemp, c, checkingBalance);
        }
        else if (accountType == 'S')
        {
            savingsBalance = balance;
            balance = sa.applyTransaction(transactionTypeTemp, amountTemp, c, savingsBalance);
        }

}

void bankAccount:: applyInterest(char accountType)
{
    double checkingBalance, savingsBalance;
    checkingAccount ca;
    savingsAccount sa;

    if (accountType == 'C')
    {
    checkingBalance = balance;
    balance = ca.applyInterest(checkingBalance);
    }
    else if (accountType == 'S')
    {
    savingsBalance = balance;
    balance = sa.applyInterest(savingsBalance);
    }


}

void bankAccount:: postPrint()
{
   cout << "Balance after processing: " << balance << endl;
}

checkingAccount:: checkingAccount()
{
    interestRate = .02;
    minimumBalance = 500;
    serviceCharge = 20;
}

void checkingAccount:: prePrint(int checkingAccountNumber, char accountType, double checkingBalance)
{
    cout << "Account Number:" << checkingAccountNumber << " account type:" << accountType << " Starting Balance:" << checkingBalance << endl;
}

double checkingAccount:: applyTransaction(char transactionTypeTemp, int amountTemp, int c, double checkingBalance)
{
  if (transactionTypeTemp == 'D')
        {
            checkingBalance = checkingBalance + amountTemp;
        }
  else if (transactionTypeTemp == 'W')
        {
            if (checkingBalance < amountTemp)
            {
            cout << "error: transaction number " << c + 1 << " never occured due to insufficent funds." << endl;
            }
            else
            {
                checkingBalance = checkingBalance - amountTemp;
                if(checkingBalance < minimumBalance) //if last transaction brought the balance below minimum balance
                {
                    checkingBalance = (checkingBalance - serviceCharge); //apply service charge
                }
            }
        }

        return checkingBalance;
}

double checkingAccount:: applyInterest(double checkingBalance)
{
    checkingBalance = (checkingBalance + (checkingBalance * interestRate));
    return checkingBalance;
}
savingsAccount:: savingsAccount()
{
    interestRate = .04;
}


void savingsAccount:: prePrint(int savingsAccountNumber, char accountType, double savingsBalance)
{
    cout << "Account Number:" << savingsAccountNumber << " account type:" << accountType << " Starting Balance:" << savingsBalance << endl;
}

double savingsAccount:: applyTransaction(char transactionTypeTemp, int amountTemp, int c, double savingsBalance)
{
  if (transactionTypeTemp == 'D')
        {
            savingsBalance = savingsBalance + amountTemp;
        }
  else if (transactionTypeTemp == 'W')
        {
            if (savingsBalance < amountTemp)
            {
            cout << "error: transaction number" << c + 1 << " never occured due to insufficent funds." << endl;
            }
            else
            {
                savingsBalance = savingsBalance - amountTemp;     //apply transaction
            }
        }

        return savingsBalance;
}

double savingsAccount:: applyInterest(double savingsBalance)
{
    savingsBalance = (savingsBalance + (savingsBalance * interestRate));
    return savingsBalance;
}

//main .cpp file
int main()
{
    ifstream inFile;
    int numberOfAccounts, accountNumTemp, transactionNum, amountTemp;
    double balanceTemp;
    char discard, accountType, transactionTypeTemp;
    bankAccount ba;

    cout << "Processing account data..." << endl;

    inFile.open("Bank.txt");

    if (!inFile)
    {
        for  (int a = 0; a < 20; a++)
            cout  << endl;
        cout << "Cannot open the input file."
             << endl;
            return 1;
    }

    inFile >> numberOfAccounts;
    inFile.get(discard);

    for (int i = 0; i < numberOfAccounts; i++)
    {
            inFile >> accountNumTemp >> accountType >> balanceTemp >> transactionNum;
            inFile.get(discard);
            ba.setAccountInfo(accountNumTemp, balanceTemp);
            ba.prePrint(accountType);

            for (int j = 0; j < transactionNum; j++)
            {
                inFile >> transactionTypeTemp >> amountTemp;
                inFile.get(discard);
                ba.applyTransaction(accountType, transactionTypeTemp, amountTemp, j);
            }
            ba.applyInterest(accountType);
            ba.postPrint();
    }


    inFile.close();

    return 0;
}

以下是copy-and-pastable形式的输入,以便其他人不必输入:

6
35231 C 500 3
W 250
W 200
W 100
46728 S 2700 2
D 250
W 100
87324 C 500 3
D 300
W 100
W 150
79873 S 800 0
89932 C 3000 2
W 1000
W 1500
98322 C 750 6
D 50
W 75
W 100
W 25
W 30
W 75

3 个答案:

答案 0 :(得分:1)

嗯...快速编译并运行您的数据,我得到以下输出:

Processing account data...
Account Number:35231 account type:C Starting Balance:500
error: transaction number 3 never occured due to insufficent funds.
Balance after processing: 10.2
Account Number:46728 account type:S Starting Balance:2700
Balance after processing: 2964
Account Number:87234 account type:C Starting Balance:500
Balance after processing: 561
Account Number:79873 account type:S Starting Balance:800
Balance after processing: 832
Account Number:89832 account type:C Starting Balance:3000
Balance after processing: 510
Account Number:98322 account type:C Starting Balance:750
Balance after processing: 484.5

这对我来说看起来很合理。在我的脑海中快速添加,“资金不足”对于第一个账户来说似乎是合理的,因为你给它的初始余额为500,并且提款加起来为550。

尽管我知道怎么做,但我认为我不会像你一样编写代码,但是我得到的输出似乎没有你所展示的问题几乎相同。 可能来自未定义的行为(例如,使用未初始化的变量),但我没有花足够的时间查看代码以确定。就我个人而言,我认为我宁愿花时间在不同的设计上而不是在代码中找到可能存在的错误,但现在它仍然存在。

编辑:就重新设计代码而言,当你需要在两个派生类中实现不同的代码时,你想要使用虚函数,并在每个派生类中适当地实现它。不是在每个成员函数中创建银行帐户作为本地变量,而是在每个成员函数中创建一个新的银行帐户对象,而是在我读取定义帐户的数据时创建一个帐户对象,然后使用该帐户对象该对象上的所有交易。

对于你是否真的甚至需要一个基类和派生类,似乎还有很多问题。我看起来并不太谨慎,但在我看来,这两种账户的行为几乎(如果不是完全相同)相同。我看到的唯一区别是,储蓄账户不允许提取负数,支票账户允许提取,但收取服务费。虽然你没有建模,但如果支票账户余额低于某一点,我很确定他们也会开始反弹支票。

在这种情况下,我认为您可以将其全部模型化为一种类型的帐户,但具有两个最低级别,并且与违反每个级别相关的费用。第一级意味着允许交易,但收取费用。第二个意味着不允许交易。

对于储蓄账户,水平和费用均设为0.0美元。对于支票账户,“收费”级别为0.0美元,“拒绝交易”级别为(比如) - 50美元。对于两者而言,费用是50美元。

答案 1 :(得分:1)

  

嗯,你的输出是正确的。你能否提出一些关于我应该从更好的设计开始的建议?

我从

开始
  • 单元测试
  • 调试程序

并跟进

  • 的valgrind

更新

我刚做了第3步(valgrind),它只是工作,提供与Jerry相同的输出:

Processing account data...
Account Number:35231 account type:C Starting Balance:500
error: transaction number 3 never occured due to insufficent funds.
Balance after processing: 10.2
Account Number:46728 account type:S Starting Balance:2700
Balance after processing: 2964
Account Number:87324 account type:C Starting Balance:500
Balance after processing: 561
Account Number:79873 account type:S Starting Balance:800
Balance after processing: 832
Account Number:89932 account type:C Starting Balance:3000
Balance after processing: 510
Account Number:98322 account type:C Starting Balance:750
Balance after processing: 484.5

请注意,这是通过这个确切的输入(我发现输入对例如案例更改非常敏感):

6
35231 C 500 3
W 250
W 200
W 100
46728 S 2700 2
D 250
W 100
87324 C 500 3
D 300
W 100
W 150
79873 S 800 0
89932 C 3000 2
W 1000
W 1500
98322 C 750 6
D 50
W 75
W 100
W 25
W 30
W 75

答案 2 :(得分:1)

伊克。

代码实际上看起来并不正确,因此您可能需要查看数据 - 您是否使用ftp移动此文件并将行结尾搞乱。

重构这个...... 首先,使用if / else编写自己的虚拟版本真是太可怕了。 第二次更新类变量通过将它们传递给成员函数并作为结果进行更新会使进程混淆。

从BankAccount ba开始;你正在为每个帐户使用它,这使得程序的其余部分更难以编写和阅读。 改为使用Factory / Lookup方法。

for (int i = 0; i < numberOfAccounts; i++)
{
        inFile >> accountNumTemp >> accountType >> balanceTemp >> transactionNum;
        inFile.get(discard);
        bankAccount &ba = bankAccount::getAccount(accountType, accountNumTemp, balanceTemp);

如果不做一个完整的工厂,它可能会像

那样
class bankAccount
{
    protected:
    bankAccount(int accountNumTemp, double balanceTemp);

    public:
    static bankAccount& getAccount( char accountType, int accountNumTemp, double balanceTemp){
        switch(accountType)
          case 'C':
            return checkingAccount(accountNumTemp, balanceTemp);
          case 'S':
            return savingsAccount(accountNumTemp, balanceTemp);
          default:
            throw exception();
        }

    }
    void prePrint();
    void postPrint();

    virtual string type() = 0;
    virtual void applyTransaction( char transactionTypeTemp, int amountTemp, int j) = 0;
    virtual void applyInterest() =0;

    protected:
    int accountNumber;
    double balance;
};

然后作为一个例子,子类将改变如

class checkingAccount: public bankAccount
{
    public:
    checkingAccount(int accountNumTemp, double balanceTemp)
        : bankAccount(accountNumTemp, balanceTemp)
    { // these are currently unchanged, could probably move to static
        interestRate = .02;
        minimumBalance = 500;
        serviceCharge = 20;
    }

    void  applyTransaction(char transactionTypeTemp, int amountTemp, int c );
    void  applyInterest();

    private:
    float interestRate;
    int minimumBalance;
    float serviceCharge;

};

void bankAccount::prePrint()
{
    cout << "Account Number:" << accountNumber 
      << " account type:" << type() 
      << " Starting Balance:" << balance << endl;
}

string checkingAccount::type(){ return "C" }

void checkingAccount:: applyTransaction(char transactionTypeTemp, int amountTemp, int c )
{
  if (transactionTypeTemp == 'D')
        {
            balance = balance + amountTemp;
        }
  else if (transactionTypeTemp == 'W')
        {
            if (balance < amountTemp)
            {
            cout << "error: transaction number " << c + 1 << " never occured due to insufficent funds." << endl;
            }
            else
            {
                balance = balance - amountTemp;
                if(balance < minimumBalance) //if last transaction brought the balance below minimum balance
                {
                    balance = (balance - serviceCharge); //apply service charge
                }
            }
        }
}

void checkingAccount:: applyInterest()
{
    balance = (balance + (balance * interestRate));
}