Advanced OOP Midterm

This take-home assignment will require you to create several new classes as well as make changes to classes from previous homework assignments. It will also implement the concept of a 'Super Base Class'.

You will have two weeks to complete it, and is due on 7/11/2000. You are to hand in a complete printout of all source and header modules, as well as a disk containing your entire project, zipped. You should delete everything in the DEBUG or RELEASE folder before zipping the files, except for the EXE file.

Please make sure to comment each function. Since this is a demonstration of polymorphism and inheritance, you will find similar comments are needed for functions across different classes.

Be sure to check the FAQ page for this class, as I will be placing questions and answers there as I get them from other students.

The Super Base Class

You must create a 'super base class', which will become the base class for all new classes, including the string class from previous homework assignments. The class should be called flObject, where fl represents your first and last initials. For now, this class will impose a simple framework, but will also introduce some very basic debugging facilities. In future lectures, this class will be extended to incorporate additional debugging features.

The class must have the following:

virtual bool SaveToFile( ofstream& Dest ) const =0;
virtual bool LoadFromFile( ifstream& Src )=0;

Note that these functions are both pure virtual functions. These functions are design to save and load the desired object to and from a disk file. The format for storage for any of the derived classes is up to you, as long as the object can read and write itself to and from the disk file.

virtual bool GetAsString( char* Dest ) const=0;
virtual bool SetFromString( const char* Src )=0;

Note that these also are pure virtual functions. The purpose of these functions is to implement a framework where objects can be 'set' from a string, or their value can be retrieved as a string (see the flDate class for an example).

This class should be in files named flObject.h and flObject.cpp. The flObject.h file may contain #include for other classes in our framework to simplify using the classes.

 

flString Class changes

You will need to take your flString class and make the following modifications to make it fit into the midterm, and our framework:

Note: It is up to you to determine how to store the strings in the file. I suggest you first store the count of characters in the string, then the string itself without it's null terminator. If the string is empty, then you need only store a zero to indicate the character length, and no characters.

flDate Class

You will need to create a new class named flDate, which will be a wrapper class for a date object. The purpose of the assignment is not to create a fully functional date class, but to create a class that fits into the framework described here. For this reason, date arithmetic and various operators you would expect to find will not be written for this class.

You will need to derive the class from the flObject class, and provide the following functions:

 

The GetAsString function has the same syntax as all other GetAsString functions:

virtual bool GetAsString( char* Dest ) const;

The function must format the date stored by the flDate object into a string. The format can be m/d/y, and you can use sprintf to create the string.

The SetMonth, SetDay, and SetYear functions should have a void return type. Some very basic date range checking is performed here. If a month is not between 1 and 12, or the day not between 1 and 31, or the year not between 1 and 3000, then the respective function should throw a character string exception indicating the error. For example:

if( m_Month<1 || m_Month > 12 )
throw "Bad Month";

 

flPerson class

You will need to create an flPerson class which contains two flString data members m_First and m_Last, and an flDate data member named m_Birthday. This class is also derived from flObject, and implements the standard framework functions:

Test program

#include "MGObject.h"
class MGPerson : public MGObject
{
public:
  virtual bool GetAsString( char* Dest ) const {
  // You must write
  }
  virtual bool SetFromString( const char* Src ) {
  // You must write
  }
  virtual bool SaveToFile( ofstream& Dest ) const {
  // You must write
  }
  virtual bool LoadFromFile( ifstream& Src ) {
  // I'll give you one example:
  if( !m_First.LoadFromFile( Src ) )
    return( false );
  if( !m_Last.LoadFromFile( Src ) )
   return( false );
  return( m_Birthday.LoadFromFile( Src ) );
}
protected:
  MGString m_First, m_Last;
  MGDate m_Birthday;
};

int main()
{
  MGString A;
  A.SetFromString( "A" );
  char Text[128];
  A.GetAsString( Text );
  cout << Text << endl;
  MGDate D;
  D.SetDay( 1 );
  D.SetMonth( 4 );
  D.SetYear( 2000 );
  D.GetAsString( Text );
  cout << Text << endl;
  char Option;
  cout << "Save or Load data file? " << endl;
  cin >> Option;
  MGPerson Person;
  if( Option == 's' || Option == 'S' ) {
  ofstream Out;
  Out.open( "midterm.dat" );
  if( !Out )
    cout << "Error opening midterm.dat file" << endl;
  else {
    Person.SetFromString( "Mario Jones 4/1/1964" );
    if( Person.SaveToFile( Out ) )
      cout << "Person saved" << endl;
    else
      cout << "Error saving person" << endl;
    }
  }
  else {
    ifstream In;
    In.open( "midterm.dat" );
    if( !In )
      cout << "Error opening midterm.dat file" << endl;
    else {
      if( Person.LoadFromFile( In ) ) {
        cout << "Person Loaded" << endl;
        Person.GetAsString( Text );
        cout << Text << endl;
      }
      else
         cout << "Error loading person" << endl;
    }
  }
  cout << "Trying exceptions: " << endl;
  try
  {
    MGDate X;
    X.SetDay( -1 );
    cout << "Bummer, should not get here" << endl;
  }
  catch( const char* E )
  {
    cout << "Cool: " << E << endl;
  }
  MGDate X;
  X.SetMonth( 12 );
  X.SetDay( 31 );
  X.SetYear( 1999 );
  X.GetAsString( Text );
  cout << "Date: " << Text << endl;
  // Allocate and throw away an MGPerson object:
  new MGPerson;
  // Then test for memory leaks:
  if( MGObject::GetCount() !=0 )
    cout << "Ok, we had a memory leak, which was expected." << endl;
  else
    cout << "Something went wrong." << endl;
  return( 0 );
}

 

Sample Output

A
4/1/2000
Save or Load data file?
l
Person Loaded
Mario Jones 4/1/1964
Trying exceptions:
Cool: Bad Day
Date: 12/31/1999
Ok, we had a memory leak, which was expected.