0

This is a Bank project I had in mind while learning C++ and I have been adding to it as I learned inheritance and pointers. The user is a bank teller who can create a new customer or process transactions of an existing customer.

A Customer has Savings and Checking classes as private fields that inherit from Account. The Bank class adds/gets customers from its private static vector<Customer> field.

The unexpected result is that in the 'process_transaction' method I can fetch a customer from vector and deposit/withdrawl from it's accounts, but once I leave the method and come back to it the accounts data hasn't changed from the time I initialized them.

Need help. It's a reference to customer issue? When should I return by reference or pointer?

Here is the code. In the driver class I have a method to create a customer

/*
* Create customer from teller input then add the Customer 
* to Bank's private static vector<Customer> field.
*/
int create_customer(){
    cout << "** Create New Customer **\n";
    cout << "Customer Name: ";
    string n = "";
    cin >> n;
    Customer* d = new Customer(n, gen_acct_number());
    Customer c(*d);
    // get opening balances
    double open_ck = 0;
    double open_sv = 0;
    cout << "Opening Balance For Checking: ";
    cin >> open_ck;

    cout << "Opening Balance For Savings: ";
    cin >> open_sv;
    cout << "\n";

    // create and set accounts
    Checking ck(open_ck);
    Savings sv(open_sv);
    c.set_checking(ck);
    c.set_savings(sv);

    // add customer to bank
    Bank b;
    b.add_customer(c);
    cout << "New Customer: " << c.get_name() << endl;
    cout << "Account Number: " << c.get_acct_number() << endl;
    cout << "\n";
    return 0;

}

I have another method in the driver class to process a customer. Once I leave this method a customer's accounts are unchanged, but works otherwise.

/*
* Fetch customer by account number from  Bank's private static 
* vector<Customer> and perform transactions on Customer's accounts
* until teller has finished processing the customer.
*/
int process_customer(){
    cout << "** Process Transaction **\n";
    cout << "Account Number: ";
    int acctNum = 0;
    cin >> acctNum;
    cout << "\n";

    // get customer
    Bank b;
    Customer c = b.get_customer(acctNum);

    //if(c* == NULL){
    //  cout << "Error: Customer Not Found.\n";
    //  return 0;
    //}

    bool flag = true;
    while(flag){
        cout << c.get_name() << " #" << c.get_acct_number() << ": ";

        cout << "Select a transaction.\n";
        cout << "1. Withdrawl\n";
        cout << "2. Deposit\n";
        cout << "3. Check Balance\n";
        cout << "4. Quit\n";
        cout << "> ";
        int choice = 0;
        cin >> choice;
        cout << "\n";

        double amt = 0;
        int which = 0;
        switch(choice){
        case 1:{    // WITHDRAWL

            cout << "Withdrawl From: \n";
            cout << "1. Checking \n2. Savings \n";
            cout << "> ";
            cin >> which;
            cout << "\n";
            cout << "Amount: ";
            cin >> amt;
            cout << "\n";

            if(which == 1){
                cout << "Old Balance: " << c.get_checking().get_balance() << endl;
                c.get_checking().withdrawl(amt);
                cout << "New Balance: " << c.get_checking().get_balance() << endl;
                cout << "\n";
            }else if (which == 2){
                cout << "Old Balance: " << c.get_savings().get_balance() << endl;
                c.get_savings().withdrawl(amt);
                cout << "New Balance: " << c.get_savings().get_balance() << endl;
                cout << "\n";
            }else{
                break;
            }
            break;
        }
        case 2:{    // DEPOSIT

            cout << "Deposit Into: \n";
            cout << "1. Checking \n2. Savings \n";
            cout << "> ";
            cin >> which;
            cout << "\n";

            cout << "Amount: ";
            cin >> amt;
            cout << "\n";
            if(which == 1){
                cout << "Old Balance: " << c.get_checking().get_balance() << endl;
                c.get_checking().deposit(amt);
                cout << "New Balance: " << c.get_checking().get_balance() << endl;
                cout << "\n";

            }else if (which == 2){
                cout << "Old Balance: " << c.get_savings().get_balance() << endl;
                c.get_savings().deposit(amt);
                cout << "New Balance: " << c.get_savings().get_balance() << endl;
                cout << "\n";
            }else{
                break;
            }
            break;
        }
        case 3:{    // CHECK BALANCE

            cout << "Checking " << c.get_checking().get_balance() << endl;
            cout << "Savings  " << c.get_savings().get_balance() << endl;
            cout << "\n";
            break;
        }
        default:{   // EXIT

            flag = false;
            break;
        }
        }
    }

    return 0;
}

The Bank class.

Bank::Bank(){}

Customer& Bank::get_customer(int acct_number) {

    for(unsigned i = 0; i < cus.size(); i++){
        if(cus[i].get_acct_number() == acct_number){
            return cus[i];
        }
    }
    return cus[0];
}
void Bank::add_customer(Customer c){
    cus.push_back(c);
}

/* Disabled. I want to pass an account to these methods.
* 
* void Bank::deposit(double amt, Account& a){
*   a.deposit(amt);
* }
* void Bank::withdrawl(double amt, Account& a){
*   a.withdrawl(amt);
* }
* double Bank::check_balance( Account& a){
*   return a.get_balance();
* }
*/


vector<Customer> Bank::cus;

Bank.h

#ifndef BANK_H_
#define BANK_H_


#include "../include/Customer.h"
#include <string>
#include <vector>
using namespace std;

class Bank{

public:
    Bank();
    Customer& get_customer(int acct_number);
    void add_customer(Customer c);
    void deposit(double amt,  Account& a);
    void withdrawl(double amt,  Account& a);
    double check_balance( Account& a);
private:
    static vector<Customer> cus;
};



#endif /* BANK_H_ */
  • Can we see the declaration of `cus`? (Which is the container of all customers hence use proper variable names) – Khalil Khalaf Aug 23 '16 at 14:03
  • `vector Bank::cus;` may be less `static` than you think. Although without the .h file, who can be sure. – infixed Aug 23 '16 at 14:08
  • An unrelated comment to your current problem: don't use `double` (or other floating point) type for amounts (as long as you don't plan to use this code ever in real application, feel free to continue with `double` of course, just don't let it slip into some real production). – Ped7g Aug 23 '16 at 14:49

1 Answers1

1

It does indeed appear to be a reference issue. In your process_customer function, change:

// get customer
Bank b;
Customer c = b.get_customer(acctNum);

to:

// get customer
Bank b;
Customer& c = b.get_customer(acctNum);

Without this change, you're making a copy of the customer and then modify this copy, instead of modifying the original customer.

Smeeheey
  • 9,906
  • 23
  • 39
  • Thank you, I knew it. Do I need to return a customer by pointer since I need to return a value for customer-not-found? – mathematted Aug 23 '16 at 14:20
  • Well at the moment you appear to return `cus[0]` when the account number is not found. As such you do need to return a pointer, you can just check whether the customer you got was this "default customer 0", for example by looking at his account number in your `process_customer` function. If you wanted to indicate the not-found condition through `nullptr` instead then yes, pointers would be easier. – Smeeheey Aug 23 '16 at 14:23
  • Okay, using pointers. Here's my solution. I found a matching customer and returned `&cus[i]` (not-found returns a null pointer), I got the return value with `Customer* resultPointer = ...`, checked it wasn't null and converted back into a value with `Customer c = (*resultPointer);` – mathematted Aug 23 '16 at 15:03
  • Don't do the last bit (`Customer c = (*resultPointer)`), otherwise you're back into modifying a copy again. Either stick to using the pointer throughout (this makes way more sense), or (less obviously and more strangely), go back to references with `Customer& c = (*resultPointer)` – Smeeheey Aug 23 '16 at 15:05
  • You are right, now it fails to modify the customer. I fixed it and it works as I would expect. Thanks – mathematted Aug 23 '16 at 15:19