-3

I'm working on a project that basically writes into a file the contents of some objects's fields data I've created(one of them being pers1, of the class PERSON);

I've inserted data into the field members of the object pers1, and I opened a file, trying to write the content of those field members(string name, surname and unsigned int age) into the file, using file.write function. It wrote parts of the contents, inbetween alot of garbage. Please help me write the proper code, so that I can write each person details into the file in a consecutive way. Thank you

   #include<iostream>
    #include<string>
    #include<fstream>
    #include <sstream>
    #include <iomanip>
    #include <list>

    class PERSON
    {
        string name;
        string surname;
        unsigned int age;
    public:
        void inputinfo()
        {
            cin>>name;
            cin>>surname;
            cin>>age;
        }
        outputinfo()
        {
            cout<<name;
            cout<<surname;
            cout<<age;
        }
    };

    class STUDENT: public PERSON
    {
        int ID;
        float marks_sum;
        string belonging_class;
    public:
        inputinfo()
        {
            cin>>name;
            cin>>surname;
            cin>>age;
            cin>>ID;
            cin>>marks_sum;
            cin>>belonging_class;
        }
    };

    void writeinfile()
    {
        PERSON pers1;
        ofstream file1
        file1.open("Students.txt", std::ofstream::out | std::ofstream::app);
        pers1.inputinfo();
        file1.write(pers1.c_str(),pers1.length()); // this is the second aproach I've found on internet, but it gives errors;
        file1.write((char*)&pers1, sizeof(pers1)); // this one is puting alot of garbage into the file, alongside fields data.
        fisier.close();
    }

    int main
    {
        int opt1, opt2;
        char option;

        switch(opt1)
        {
        case 1:
            do
            {
                cout<<endl;
                        <<"Choose one of variants"<<"1.Students"<<"2.Teachers"<<"3.Get back to main menu"<<endl;
                cin>>opt2;
                switch(opt2)
                {
                case 1:
                    do
                    {
                        cout<<"Do you wish to introduce a new student(Y/N)?";
                        cin>>option;
                        if(option!='N')
                            writeinfile()
                    } while(option!='N');
                            break;
                    default:
                        cout<<"Incorect!"<<endl;
                    }
                    while(opt2!=3);
                    break;
                case 2: "...."
                    ;
                    break
                case 3: "...."
                    ;
                    break;
                }
            }
        }

I expect clean write of field data into the file, everytime I call the aforementioned function. For example for 1st iteration, when I enter data into the object's field: name : John, surname: Doe, age: 45, I espect to see this data into a single line in the file(and no garbage inbetween).

painkiller
  • 149
  • 6
  • what is PERSON ? – Oblivion Oct 13 '19 at 11:54
  • It's the base class, and pers1 is an object of that class. – painkiller Oct 13 '19 at 11:56
  • please show the code. write like us has no idea what PERSON is. – Oblivion Oct 13 '19 at 11:57
  • 1
    You probably want something like `file1 << pers1.one_member << ", " pers1.another_member << ... << '\n';`. – Some programmer dude Oct 13 '19 at 12:01
  • This c style cast is really bad: (char*)&pers1 – Oblivion Oct 13 '19 at 12:01
  • *It's the base class* - I hope you mean "Its a *class*", because otherwise this will eventually be a recipe for [slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing) at best, and if `PERSON` and its derivations are non-POD types, far worse than that. – WhozCraig Oct 13 '19 at 12:03
  • yes, it's the base class. And for Oblivion, I've edited the post with info about PERSON – painkiller Oct 13 '19 at 12:05
  • yes, Some programmer dude, that's exactly what I want, but it doesn't work properly. – painkiller Oct 13 '19 at 12:06
  • file1.write(pers1.name.c_str(),pers1.name.length()); should work. I don't see inheritance in your code. You should do the same for other members too. The better approach is overloading the operator. – Oblivion Oct 13 '19 at 12:09
  • Usually you write yourself a function looking like this: ``std::ostream& operator<<( std::ostream& os, const PERSON& value) { ... ; return os; }``. With that, you can "serialize" your persons both to ``std::cout`` and to files. Or to strings with ``std::stringstream`` or any of the other mutations. – BitTickler Oct 13 '19 at 12:13
  • Well, there is inheritance, but that would mean to put the whole code, and it's way too big. On the short side, The PERSON class is a base class for the subclass STUDENT, which inherits PERSON's fields (name, surname, and age), and adds 3more: ID, mark, class_id (ex:the 10th grade, the 5th grade, etc). What I'm trying to acomplish, is to write the STUDENT's fields into the file, one student at a time. But for the moment I'm testing with the fields of the base class first to see how it goes. – painkiller Oct 13 '19 at 12:13
  • WhozCraig, I'm afraid PERSON is indeed a base clase, and STUDENT a derived class of it...that's why I posted here, it's way too complicate to only search endlessly on google for solutions... – painkiller Oct 13 '19 at 12:34
  • 1
    Please provide a [mcve]. That doesn't mean that you copy the whole code or that you copy some snippets. Create an example that contains this inheritance. – Thomas Sablik Oct 13 '19 at 12:35
  • I've updated the partial code, with the inheritance and all. What I actually want is to insert STUDENT's data from fields( both inherited, and its own) into a file, one student-one line. That's all. – painkiller Oct 13 '19 at 16:06
  • @painkiller Could you please fix the complete lack of indentation sprinkled with random indentation? Reading your code is more work than it's worth. – Carey Gregory Oct 13 '19 at 16:20
  • @Carey Gregory I fixed the indentation. I hope it looks more readable now. :D – painkiller Oct 13 '19 at 17:57

1 Answers1

1
#include <iostream>
#include <fstream>

std::ostream& operator<< (std::ostream& os, const PERSON& value )
{
    // here, you decide how the output format should look like. See below.
    // ...
    return os;
}

std::istream& operator>> (std::istream& is, PERSON& value )
{
    // here, you do the reverse of what you chose in operator<<(). See below.
    // ...
    return is;
}

While you will be able to quickly hack an implementation to those 2 functions, it is worth while thinking of the requirements of what you want to accomplish:

  • Maintenance? What happens to your files in the future when you change your PERSON (e.g. extra fields)? Do you still want to be able to use those old files?
  • Robustness. Will you have to pay attention to localization? What will happen if your first Chinese Student arrives with a Kanji name? Do you need utf8 encoding or alike? Will you encounter "missing values"?
  • Scalability? Will you end up writing your own little data base with your own SQL to later on query for subsets of persons? Will you still be able to read the whole file once it has grown beyond expectations? Will new files with other data arrive and later there will be the need to associate them? (OUTER JOIN, INNER JOIN,...)

As you can see from this short and certainly incomplete list, you are at a cross road here: Use database instead? Use a standard serialization format like XML or JSON or protocol buffers or FastNProto or whatever is fashionable today? Or just go ahead and do your own thing as it is all a quick and dirty thing anyway?

Now, to the practical things:

Inside your operator<<, you can "dump" your elements like this (sticking to what you wrote in the question):

os << "name: " << value.name.c_str() 
   << ", surname: " << value.surname.c_str() 
   << ", age: " << value.age 
   << std::endl;

And to read it back in, you implement the operator>> accordingly.

std::string tag;
is >> tag; // optionally make sure it is "name:"
is >> value.name;
// ... (The commas might need some fiddling... well you wanted help not a full solution...)

Then, all you need to do is test it, e.g. using a string stream, serialize a person, read it into another instance and compare. And you should be done ;)

BitTickler
  • 10,905
  • 5
  • 32
  • 53