Note: I apologize if this program is painful to look at. this is my first program using derived classes. I plan on submitting it to code review after I get it to do what I want so I can recieve tips on how it could have been designed better. Feel free to provide those tips here but my main intention for this post is to get it to work correctly.
This program processes withdrawals and deposits for bank accounts and then applies an interest rate.
the problem: For some reason it seems like the value of checkingBalance gets stuck and does not update to a new value throughout the rest of the loop when processing the accounts of class type “checkingAccount”. It is odd because the same loop is used to process the other derived class “savingsAccount” and it works fine and one of accounts of type “checkingAccount” even seems to have been processed correctly so I am completely bamboozled as to what is going on.
If anyone could lend a hand and help me resolve this issue it would be greatly appreciated. Please do not hesitate to ask me to specify anything, I will respond asap.
the data being read:

The output:

The code I suspect the issue to be in:
//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;
}
the whole program:
//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;
}
Here is the input in copy-and-pastable form so that others don’t have to type it in:
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
Hmm…doing a quick compile and run with your data, I get the following output:
Most of this looks fairly reasonable to me. Doing a quick addition in my head, the “insufficient funds” seems reasonable for the first account since you’re giving it an initial balance of 500, and the withdrawals add up to 550.
To put it as nicely as I know how, I don’t think I’d write the code the same way you have, but the output I’m getting doesn’t seem to have nearly the same problems you’ve shown. That could be from undefined behavior (e.g., using an uninitialized variable), but I haven’t spent enough time looking through the code to be sure. Personally, I think I’d rather spend my time on a different design than on finding possible bugs in the code as it stands right now though.
Edit: As far as re-designing the code goes, when you have code that needs to be implemented different in the two derived classes, you want to use a virtual function, and implement it appropriately in each derived class. Instead of creating bank accounts as local variables in each member function, and creating a new bank account object in each, I’d create one account object as I’m reading in the data that defines an account, and then use that account object for all the transactions on that object.
It also seems to be open to considerable question whether you really even need a base class and derived classes at all. I didn’t look too carefully, but it looks to me like the behavior of the two types of accounts is pretty much (if not completely) identical. The only difference I saw was that a savings account doesn’t allow a withdrawal into negative numbers, where a checking account does allow such withdrawals, but charges a service charge. Though you don’t model it, if a checking account balance drops below some point, I’m pretty sure they’ll start to bounce checks as well.
That being the case, it looks to me like you could model it all as one type of account, but with two minimum levels, and a fee associated with violating each. The first level means the transaction is allowed, but a fee is charged. The second means the transaction is not allowed.
For a savings account, both levels and fees are set to $0.0. For a checking account, the “charge fee” level is $0.0, and the “refuse transaction” level is (say) -$50. For both, the fee is, say, $50.