views:

449

answers:

2

Hi, I quite recently learned about the C++ classes friend keyword and the uses in serialization and now I need some help in getting it to work.

I have no problem serializing my class to a file, it's working great, however i'm having a hard time trying to read this file into a vector container. I'm sure I need a loop in my code that reads line by line, but since the class has different types I guess I can't use std::getline() and also maybe that approach wouldn't use the istream method i implemented? A sample output file would be:

Person 1
2009
1

Person 2
2001
0

My code:

class SalesPeople {
    friend ostream &operator<<(ostream &stream, SalesPeople salesppl);
    friend istream &operator>>(istream &stream, SalesPeople &salesppl);

    private:
        string fullname;
        int employeeID;
        int startYear;
        bool status;
};

ostream &operator<<(ostream &stream, SalesPeople salesppl)
{
    stream << salesppl.fullname << endl;
    stream << salesppl.startYear << endl;
    stream << salesppl.status << endl;
    stream << endl;
    return stream;
}

istream &operator>>(istream &stream, SalesPeople &salesppl)
{
    stream >> salesppl.fullname;
    stream >> salesppl.startYear;
    stream >> salesppl.status;
    // not sure how to read that empty extra line here ?
    return stream;
}

// need some help here trying to read the file into a vector<SalesPeople>
SalesPeople employee;
vector<SalesPeople> employees;

ifstream read("employees.dat", ios::in);
if (!read) {
   cerr << "Unable to open input file.\n";
   return 1;
}

// i am pretty sure i need a loop here and should go line by line 
// to read all the records, however the class has different
// types and im not sure how to use the istream method here.

read >> employee;
employees.push_back(employee);

By the way, I know that the Boost library has a great serialization class, however I'm trying to learn how serialization would work using the STL library for now. Thanks a lot in advance for any help that you can give me and for getting me in the right track!

+1  A: 

Not sure what your problem is. What exactly are you not understanding ? The fact that your names are composed of multiple tokens ? There's no magic way to do it, you might want to get the name trough getline(). Alternatively, you may want to specify the number of tokens when serializing and read the appropriate token count. ie, your file might look like.

2 Person 1

I assumed that Person was the first name and 1 the last name here. You might also enforce the notion that there's one first name, and one last name and just read each one separately.

You'll typically loop while (!ifstream.eof()) and read. Of course, you should always validate the inputs.

Also, why are you adding an extra endl between each record ? Serialized data need not be pretty. :)

jfclavette
+2  A: 

It looks like you pretty much have all the code you need already! I copied your code and compiled it with some changes to read the SalesPeople in from a file in a loop. I will include the changes below, but since this is for your homework, you may just want to read and think about the following hints before looking at the code.

  • For reading the SalesPeople in a loop, I would recommend that you take a look at this FAQ. It has an example of almost exactly what you need. FAQ 15.4 will also help you, I believe.

  • For your question on how to handle the extra empty line when reading from the file, check out this link. You can very simply extract whitespace this way.

  • As jfclavette suggested, I would recommend looking into std::getline for reading in the SalesPerson's full name, since you need everything on that line into one string.

I have one question for you, though: what about the employeeID? I notice that it is being ignored in your sample code. Is that on purpose?

And now, if you still need help, you can check out the code I wrote to get this to work:

istream &operator>>(istream &stream, SalesPeople &salesppl)
{
    //stream >> salesppl.fullname;
    getline(stream, salesppl.fullname);
    stream >> salesppl.startYear;
    stream >> salesppl.status;
    // not sure how to read that empty extra line here ?
    stream >> ws;
    return stream;
}

while(read >> employee)
{
    // cout << employee; // to verify the input, uncomment this line
    employees.push_back(employee);
}

Also, as jfclavette suggested, it may not be a bad idea to add some input validation (check the stream status after reading from it and verify that it is still good). Although I would recommend using the while() loop for the reasons stated in FAQ 15.5.

Venesectrix
Thank you so much!!!!That helped a lot! Now I understand much better what I was doing wrong.Also, I had no idea about ws, I have been wondering how to do that for a long time! Thank you so much!
nmuntz
No problem, glad I could help!
Venesectrix