Link to home
Start Free TrialLog in
Avatar of andrew161
andrew161

asked on

writing an object to a file

I have an polymorphic object.  I'm trying to allow the user of my program to save the object for future use.

The base class of the object has a bunch of subclasses and some virtual methods.  The derived classes have subclasses.  I want to save the instances of the derived classes that the user creates by using the program.  How would i go about doing this?  The filestream methods dont seem to be working properly.
Avatar of Jan Louwerens
Jan Louwerens
Flag of United States of America image

What you describe is called object serialization. I know this doesn't answer your question, but it might help you to narrow down your search for more info.
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of pitonyak
pitonyak


There are many ways to do this.... One common method is as follows:

For every class, define virtual functions called read_data and write_data.

Assume something like this...

class BaseClass {
public:
   ostream& write_data(ostream& os) const;
   istream& read_data(istream& is);

protected:
};

ostream& BaseClass::write_data(ostream& os) const
{
    // stream all of the data from this class to the ostream.
   return os;
}

istream& BaseClass::read_data(istream& is)
{
    // stream all of the data from this class from the istream.
   return is;
}

class D : public BaseClass {
public:
   ostream& write_data(ostream& os) const;
   istream& read_data(istream& is);

protected:
   BaseClass object_;
   int x_;
};

ostream& D::write_data(ostream& os) const
{
    // stream all of the data from this class to the ostream.
    // remember that I have not run this code to work out the bugs.
   BaseClass::write_data(os);
   object_.write_data(os);
   os << x_ << endl;
   return os;
}

istream& D::read_data(istream& is)
{
    // stream all of the data from this class from the istream.
    // remember that I have not run this code to work out the bugs.
   BaseClass::read_data(os);
   object_.read_data(os);
   os >> x_; // remember to eat the endl... verify the best way to do this.
   return is;
}


This, of course, assumes that you know exactly what you have written and
in what order. You may have to do things in a more complicated manner including type indentifiers and then have a class builder...

Andy
Int the following example, the base class and the derived classes both defien input() and output() functions that allow the classes to be read and written.  The derived classes uses the base class version of the procedures to help it do it s work.

class Base
{
   int BX;
   double BD;
public:
   // output function
   void Output(ostream &Out)
   {
      Out << ' ' << BX << '  ' << BD; // Write the data members.
   };
   // Input function.
   void Input(istream &In)
   {
      In >> BX >> BD; // Read data members.
   };
};

class Derived : public Base
{
   int DX;
   double DD;
public:
   // output function
   void Output(ostream &Out)
   {
      Base::Output(Out); // write the base class
      Out << ' ' << DX << '  ' << DD; // Write the data members.
   };
   // Input function.
   void Input(istream &In)
   {
      Base::Input(Int); // Read the base class
      In >> BX >> BD; // Read data members.
   };
};

continues
Now both the classes had simple (built-in) data types as members, if a class has another class as a data member, you can use that class's input() and output() member functions to help you, like

class Complex
{
   int CX;
   Derived D;
public:
   // Output function
   void Output(ostream &Out)
   {
      Out << ' ' << CX; // Write the built-in data members.
      D.Output(Out); // Write the class data member.
   };
   // Input function.
   void Input(istream &In)
   {
      In >> CX >> BD; // Read the built-in data members.
      D.Output(In); // Read in the class data member.
   };
};
Now if a class has a pointer data member, you don't want to write out the pointer, instead you want to the data that the pointer points to.  When you read n the data, you want to allocate an object for the pointer to point to  (if it doesn't already point to something) and then read the data into the object that it points to.  Things get more complex if the data point to is an array and the size of the array can varry.  For this case you can write out a size for the array and then write out the data in the array.  When you read the array, you read the size and then allocate a new array of that size.

class Array
{
   int ItemCount; // Number of items in the array
   Derived *ArrayPtr; // -> to the array of items stored.
public:
   // Output function
   void Output(ostream &Out)
   {
      Out << ' ' << ItemCount; // Write the number of items.
      for (int i = 0;  i < ItemCount; ++i)
          ArrayPtr[i].Output(Out); // Write the an oject form the array.
   };
   // Input function.
   void Input(istream &In)
   {
      delete [] ArrayPtr; // Delete the old array.

      In >> ItemCount; // Read the number of items.
      ArrayPtr = new Derived[ItemCount]; // Allocate the items.
      for (int i = 0;  i < ItemCount; ++i)
         ArrayPtr[i].Input(In); // Read an object from the array.
   };
}
Let me know if you have any questions.