Search code examples
c++ofstream

Reading in an object that is a data member of another object C++


I have a program that creates three Person objects (name and address as data members) and then creates three Account objects (person object, account number, and account balance as data members). It then writes the data members from the accounts objects to a file and then clears the account objects. The program is then supposed to create new account objects and read in their data members from the same file and push them to a vector. That vector is used to display the data members.

The problem I am having is with reading in the account objects. Specifically reading in the person objects inside the account objects. I know that person objects should be the only ones accessing its data members. I just can't seem to get it to work. Everything compiles fine but it throws an exception when the object reads itself in.

Here is the associated code. I'll include just the readData methods for both classes and the entire driver.cpp code. Let me know if you need to see more.

Thank you!

Account.cpp

void Account::readData(ifstream &ifile)
{
    if (ifile.fail() || ifile.bad())
    {
        throw readFileException("Could not read file [account]");
    }
    else 
    {
        ifile >> accountNumber;
        ifile >> accountBalance;
        accountPerson.readData(ifile);
    }
}

Person.cpp

void Person::readData(ifstream &ifile)
{
    if (ifile.fail() || ifile.bad())
    {
        throw readFileException("Could not read file [person]");
    }
    else
    {
        getline(ifile, name);
        getline(ifile, address);
    }
}

Driver.cpp

#include "Driver.h"

using namespace std;

int main()
{

    vector<Account> a;

    Person john("John Stockton", "1 Jazz lane");
    Person karl("Karl Malone", "2 Jazz Ave");
    Person jerry("Jerry Sloan", "3 Jazz Street");

    Account a1(john, 1, 500.00);
    Account a2(karl, 2, 1000.00);
    Account a3(jerry, 3, 1200.00);

    a.push_back(a1);
    a.push_back(a2);
    a.push_back(a3);

    ofstream outFile("accounts.txt");

    for (int i = 0; i < a.size(); i++) //to write account info to accounts.txt
    {
        a[i].writeData(outFile);
    } //end for loop

    outFile.close();  // to close accounts.txt

    a.clear(); // clear vecter of accounts -- size now 0

    ifstream inFile("accounts.txt");

    while (!inFile.eof()) //Loop to read in accounts and push them to vector
    {
        Account b;
        try
        {
            b.readData(inFile);
            a.push_back(b);
        }
        catch (readFileException &e)
        {
            cout << "Error: " << e.getMessage() << endl;
            system("pause");
            exit(1);
        }
    } // end of while loop

    for (int i = 0; i < a.size(); i++)
    {
        a[i].deposit(DEPOSIT_AMNT);
    }//end for loop
    for (int i = 0; i < a.size(); i++)
    {
        a[i].withdraw(WITHDRAW_AMNT);
    }//end for loop

    displayAccounts(a);

    system("pause");
    return 0;
}

void displayAccounts(const vector<Account>& v)
{
    //To display column headings
    cout << fixed << setprecision(PRECISION);
    cout << setw(COLUMN_WIDTH_SHORT) << "Acct #" << setw(COLUMN_WIDTH_LONG)
        << "Name" << setw(COLUMN_WIDTH_LONG) << "Address"
        << setw(COLUMN_WIDTH_LONG) << "Balance" << endl;

    for (int i = 0; i < v.size(); i++)
    {
        Person p; 
        p = v[i].getPerson();

        cout << setw(COLUMN_WIDTH_SHORT) << v[i].getAccountNumber() << setw(COLUMN_WIDTH_LONG)
            << p.getName() << setw(COLUMN_WIDTH_LONG) << p.getAddress()
            << setw(COLUMN_WIDTH_LONG) << v[i].getAccountBalance() << endl;
    }//end for loop
}

The accounts.txt file is written like this:

1
500
John Stockton
1 Jazz lane
2
1000
Karl Malone
2 Jazz Ave
3
1200
Jerry Sloan
3 Jazz Street

Solution

  • Your code doesn't work because you are checking the input file for "failure" in the wrong way. You should never use while (!infile.eof), instead you should check each input operation as you go. For example:

    if (!(ifile >> accountNumber))
    
    if (!(getline(ifile, name)))
    

    This way you also do not need to check for bad() and fail(). Instead, just run until an input operation fails.

    For more detail on why your while loop doesn't work, see here: https://stackoverflow.com/a/4533102/4323