Link to home
Start Free TrialLog in
Avatar of coririzzo
coririzzo

asked on

Follow up to Q_21224177- having trouble rewriting functions to use the new class EMailList

My original code consisted of main.cpp, EMailObjs.h, and EMailObjs.cpp.  I have added the class EMailList.h from Alex's solution.  Now I need to modify the functions listEMailObjs, updateRecord, insertRecord, and deleteRecord (which are called from the switch) and add them to the EMailList class (need to access the EMailObjs through EmailList and not directly).  I am having trouble figuring out how to modify the code.  Any help would be appreciated.  Here are the files:

//main.cpp
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include "EMailObjs.h"
#include "EmailList.h"

using namespace std;

// function prototypes for managing the file
void initializeFile( fstream & );
void inputData( fstream & );
void listEMailObjs( fstream & );
void updateRecord( fstream & );
void insertRecord( fstream & );
void deleteRecord( fstream & );
int instructions( void );
void read_integer ( istream&, int&);  //function to handle non-integer input

enum InputError {
   NotAnInteger,
   SomethingUnknown
};

void main()
{
    int choice;
      char response;
   
   // file stream used for input and output
  fstream file( "C:\\names.dat", ios::in | ios::out );
     
   // terminate program if file cannot be opened
   if ( !file ) {
      cerr << "File could not be opened.\n";
      exit( EXIT_FAILURE );
   } // end if

   // ask user if new file should be made
   cout << "Should the file be initialized (Y or N): ";
   cin >> response;  

   // test if users response was valid
   while ( toupper( response ) != 'Y' && toupper( response ) != 'N' ) {
      cout << "Invalid response. Enter Y or N: ";
      cin >> response;
   } // end while

   // initialize file if user says too
   if ( toupper( response ) == 'Y' ) {
      initializeFile( file );
      inputData( file );
   } // end if

   // perform user instructions until 5 is entered
   while ( ( choice = instructions() ) != 5 ) {
            switch (choice){
            case 1:      listEMailObjs(file );
                  break;
            case 2:      updateRecord(file );
                  break;
            case 3:      insertRecord(file );
                  break;
            case 4:      deleteRecord(file);
                  break;
            default:      cout<< "Error";
                  break;
         }
      file.clear();    // reset eof indicator
   } // end while

   file.close(); // close input/output file
} // end main

// function to clear file
void initializeFile( fstream &fRef )
{
   EMailObjs blankItem;  // empty EMailObjs object

   // fill file with blank records
   for ( int i = 0; i < 100; ++i )
      fRef.write( reinterpret_cast< char * >( &blankItem ), sizeof( EMailObjs ) );
} // end function initializeFile

void inputData( fstream &fRef )
{
   EMailObjs temp;  // temporary EMailObjs object

   // temporary variables used to hold user input
      int number;
      char Aname[LENGTH];                  
      char Aemail[LENGTH];      
      char Awebsite[LENGTH];

   // ask user for and set partNumber
   cout << "Enter the record number (0 - 99, -1 to end input): ";
   cin >> number;
   temp.setRecordNumber( number );

   // set EMailObjs members until Q is entered
   while ( temp.getRecordNumber() != -1 ) {
        cout << "Enter the name: "; // ask user for name
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aname, LENGTH );   // store namel in temporary variable name
        temp.setName( Aname );  // set name
      cout << "Enter the email address: "; // ask user for email address
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aemail, LENGTH );   // store EMail in temporary variable
      temp.setEmailAddress( Aemail );  // set EMail address
      cout << "Enter the website: ";  // ask user for website
        cin.ignore();  // ignore the newline on the input stream
      cin.get( Awebsite, LENGTH );  // store input in temporary variables
      temp.setWebsite( Awebsite );  // set website
       
      // place file-position pointer at next write location
      fRef.seekp( ( temp.getRecordNumber() ) * sizeof( EMailObjs ) );

      // write data to file
      fRef.write( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );

      // ask user for next part number
      cout << "Enter the record number (0 - 99, -1 to end input): ";
      cin >> number;
      temp.setRecordNumber( number );
   } // end while
} // end inputData

//function to handle non-integer input for variable choice
void read_integer ( istream& is, int& i) {

  int n;
  string str;
  char* pcCnvEnd = NULL;

  getline(is,str); // read input

  n = (int) strtol(str.c_str(),&pcCnvEnd,10); // try to convert the string to int

  if ( *pcCnvEnd) // conversion did not end at the term. NULL -> invalid input
    throw NotAnInteger;

  i = n; // conversion successful, was an int
}

// function that decides what choice user selected
int instructions( void )  //contains exception handling for non integer entry
{
int choice;
// ask user to enter a choice
cout << "\nEnter a choice:\n" <<
            "1  List all records.\n" <<
            "2  Change record.\n" <<
            "3  Add a record.\n" <<
            "4  Delete a record.\n" <<
            "5  Quit.\n";
// ask user for choice until a valid choice is entered
do {
  try {
    read_integer(cin,choice);
  }
  catch ( InputError e) {
     if ( NotAnInteger == e) cout << "NotAnInteger\n";
       else cout << "Something unknown went wrong\n";
     continue;
  }
 } while ( choice < 1 || choice > 5 );
return choice; // return user choice
} // end function instructions

// function that lists tools in file
void listEMailObjs( fstream &fRef )
{
   EMailObjs temp;
   // display column headings
   cout << '\n' << setw( 3 )  << " " << left
        << setw( 12 ) << "Name" << left
            << setw( 20 ) << "EMail" << left
            << setw( 20 ) << "Website" << left
        << '\n';
   // continue until 100 EMailObjss are displayed or end of file reached
   for ( int count = 0; count < 100 && !fRef.eof(); ++count ) {
      // set file position pointer and begin reading
      fRef.seekg( count * sizeof( EMailObjs ) );      
      fRef.read( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );
      // if part number is valid, display EMailObjs information
      if ( temp.getRecordNumber() >= 0 && temp.getRecordNumber() < 100 ) {
              cout << setw( 2 ) << temp.getRecordNumber() << " " 
              << left << setw( 12 ) << temp.getName().data()
              << left << setw( 20 ) << temp.getEmailAddress().data()
                    << left << setw( 20 ) << temp.getWebsite().data()
              << '\n';
      } // end if
   } // end for
} // end function listEMailObjss

// function to update a EMailObjs's information
void updateRecord( fstream &fRef )
{
   EMailObjs temp;
   int number;
      char Aname[LENGTH];                  
      char Aemail[LENGTH];      
      char Awebsite[LENGTH];
   // ask user what part to update
   cout << "Enter the record number for update: ";
   cin >> number;
   // set file positions pointer to correct EMailObjs
   fRef.seekg( number * sizeof( EMailObjs ) );
   // read EMailObjs information
   fRef.read( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );
   // display EMailObjs information if partNumber is not -1
   if ( temp.getRecordNumber() != -1 ) {
      cout << '\n' << setw( 3 ) << " " << left
        << setw( 12 ) << "Name" << left
            << setw( 20 ) << "EMail" << left
            << setw( 20 ) << "Website" << left
        << '\n';

         cout << setw( 2 ) << temp.getRecordNumber() << " " 
              << left << setw( 12 ) << temp.getName().data()
              << left << setw( 20 ) << temp.getEmailAddress().data()
                    << left << setw( 20 ) << temp.getWebsite().data()
              << '\n';
        cout << "Enter the new name: "; // ask user for new name

      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aname, LENGTH );   // set new name
      temp.setName( Aname );  
      cout << "Enter the new email address: "; // ask user for email address
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aemail, LENGTH );   // store EMail in temporary variable
      temp.setEmailAddress( Aemail );  // set EMail address
      cout << "Enter the new website: ";  // ask user for website
        cin.ignore();  // ignore the newline on the input stream
      cin.get( Awebsite, LENGTH );  // store input in temporary variables
      temp.setWebsite( Awebsite );  // set website
      // set file position pointer and write information to file
      fRef.seekp( ( temp.getRecordNumber() ) * sizeof( EMailObjs ) );
      fRef.write( reinterpret_cast< char * > ( &temp ), sizeof( EMailObjs ) );
  } // end if
   else
     cerr << "Cannot update. The record is empty.\n";
} // end function updateRecord

// function to insert a new record
void insertRecord( fstream &fRef )
{
      EMailObjs temp;
      int number;
      char Aname[LENGTH];                  
      char Aemail[LENGTH];      
      char Awebsite[LENGTH];
   // ask user for record number
   cout << "Enter the record number for insertion: ";
   cin >> number;
   // set file position pointer and read data from file
   fRef.seekg( ( number ) * sizeof( EMailObjs ) );
   fRef.read( reinterpret_cast< char * > ( &temp ), sizeof( EMailObjs ) );
   // as long as record is empty get information from user
   if ( temp.getRecordNumber() == -1 ) {
      temp.setRecordNumber( number );   // set recordNumber
      cout << "Enter the name: "; // ask user for name
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aname, LENGTH );
      temp.setName( Aname );  // set Name
      cout << "Enter the email address: "; // ask user for email address
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aemail, LENGTH );   // store EMail in temporary variable
      temp.setEmailAddress( Aemail );  // set EMail address
      cout << "Enter the website: ";  // ask user for website
        cin.ignore();  // ignore the newline on the input stream
      cin.get( Awebsite, LENGTH );  // store input in temporary variables
      temp.setWebsite( Awebsite );  // set website

      // set file position pointer and write information to file
      fRef.seekp( ( temp.getRecordNumber() ) * sizeof( EMailObjs ) );
      fRef.write( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );
  } // end if
   else
      cerr << "Cannot insert. The record contains information.\n";
} // end function insertRecord

// function to delete a record
void deleteRecord( fstream &fRef )
{
   EMailObjs blankItem;
   EMailObjs temp;
   int number;
   // get tool user wants to delete
   cout << "Enter the record number for deletion: ";
   cin >> number;
   // set file position pointer and read information from file
   fRef.seekg( number * sizeof( EMailObjs ) );
   fRef.read( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );
   // if record contains data, set record to an empty EMailObjs object
   if ( temp.getRecordNumber() != -1 ) {
      fRef.seekp( number * sizeof( EMailObjs ) );
      fRef.write( reinterpret_cast< char * >( &blankItem ), sizeof( EMailObjs ) );
      cout << "Record deleted.\n";
    } // end if
   else
      cerr << "Cannot delete. The record is empty.\n";
} // end function deleteRecord
/////////////////////////////////////////////////////////////////////////////////////
//EmailObjs.h
#ifndef EMAILOBJS_H
#define EMAILOBJS_H

#include <iostream>
using namespace std;

const int LENGTH = 50;

class EMailObjs
{
public:
      EMailObjs(int= -1, string = "", string = "", string = "");  //default constructor
      void setRecordNumber( int );
    int getRecordNumber() const;
      void setName(string);
      string getName()const;
      void setEmailAddress(string);
      string getEmailAddress()const;
      void setWebsite(string);
      string getWebsite()const;
private:
      int recordNumber;
      char name[LENGTH];                  // name of person or company
      char email[LENGTH];                  // email address
      char website[LENGTH];            // website address
};
#endif
/////////////////////////////////////////////////////////////////////////
//EMailObjs.cpp
#include <iostream>
using namespace std;

#include "EMailObjs.h"

EMailObjs::EMailObjs(int recordNumberValue, string nameValue, string emailValue, string websiteValue)
{
      setRecordNumber( recordNumberValue );
      setName(nameValue);
      setEmailAddress(emailValue);
      setWebsite(websiteValue);
}

void EMailObjs::setRecordNumber( int recordNumberValue )
{
   recordNumber = recordNumberValue;
}

int EMailObjs::getRecordNumber() const
{
   return recordNumber;
}

void EMailObjs::setName(string nameString)
{
      const char *nameValue = nameString.data();
      int length = strlen(nameValue);
      length = (length < 50 ? length : 49);
      strncpy(name, nameValue, length);
      name[length] = '\0';
}

string EMailObjs::getName()const
{
      return name;
}

void EMailObjs::setEmailAddress(string emailString)
{
      const char *emailValue = emailString.data();
      int length = strlen(emailValue);
      length = (length < 50 ? length : 49);
      strncpy(email, emailValue, length);
      email[length] = '\0';
}

string EMailObjs::getEmailAddress()const
{
      return email;
}

void EMailObjs::setWebsite(string websiteString)
{
      const char *websiteValue = websiteString.data();
      int length = strlen(websiteValue);
      length = (length < 50 ? length : 49);
      strncpy(website, websiteValue, length);
      website[length] = '\0';
}

string EMailObjs::getWebsite()const
{
      return website;
}
/////////////////////////////////////////////////////////////////////////////////////////
//EMailList.h
#ifndef EMAILLIST_H
#define EMAILLIST_H
#include <iostream>
#include <vector>
using namespace std;

class EMailList
{
public:
       EMailList(const string& strFileName = "c:\\names.dat", int maxSize = 100)
               : m_strFileName(strFileName), m_maxSize(maxSize) {}
       virtual ~EMailList() { for (int i = 0; i < m_pObjs.size(); ++i) delete m_pObjs[i]; }

       EMailObjs* createEmailObj(int rec, const string& name, const string& mailaddr,
                                              const string& webaddr)
       {  if (rec < 0 || rec >= m_maxSize) return NULL; // invalid rec
          if (rec >= m_pObjs.size() && 
              m_pObjs[rec] != NULL) return NULL;  // rec already used
          for (int i = m_pObjs.size(); i < rec; ++i)
                m_pObjs.push_back(NULL);   // add NULL pointers between if not contigous
          m_pObjs.push_back(new EMailObjs(rec, name, mailaddr, webaddr));
          return m_pObjs[rec];
       }
       EMailObjs* getEmailObj(int rec)
       {   if (rec < 0 || rec >= m_pObjs.size() ) return NULL; // invalid rec
            return m_pObjs[rec];
       }
       bool removeEmailObjs(int rec);
            
private:
      string             m_strFileName;
      int                m_maxSize;
      vector<EMailObjs*> m_pObjs;
};
#endif
Avatar of Axter
Axter
Flag of United States of America image

You could get an answer faster and better, if you post a specific question, or a more detailed question.
Avatar of coririzzo
coririzzo

ASKER

OK, the function update Record needs to be a member function of the class EMailList.  The data needs to be accessed through a vector element of EMailList rather than by using "EMailObjs temp" to directly access the EMailObjs class.

void updateRecord( fstream &fRef )
{
   EMailObjs temp;
   int number;
     char Aname[LENGTH];              
     char Aemail[LENGTH];    
     char Awebsite[LENGTH];
   // ask user what part to update
   cout << "Enter the record number for update: ";
   cin >> number;
   // set file positions pointer to correct EMailObjs
   fRef.seekg( number * sizeof( EMailObjs ) );
   // read EMailObjs information
   fRef.read( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );
   // display EMailObjs information if partNumber is not -1
   if ( temp.getRecordNumber() != -1 ) {
      cout << '\n' << setw( 3 ) << " " << left
        << setw( 12 ) << "Name" << left
          << setw( 20 ) << "EMail" << left
          << setw( 20 ) << "Website" << left
        << '\n';

         cout << setw( 2 ) << temp.getRecordNumber() << " " 
              << left << setw( 12 ) << temp.getName().data()
              << left << setw( 20 ) << temp.getEmailAddress().data()
                 << left << setw( 20 ) << temp.getWebsite().data()
              << '\n';
        cout << "Enter the new name: "; // ask user for new name

      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aname, LENGTH );   // set new name
      temp.setName( Aname );  
      cout << "Enter the new email address: "; // ask user for email address
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aemail, LENGTH );   // store EMail in temporary variable
      temp.setEmailAddress( Aemail );  // set EMail address
      cout << "Enter the new website: ";  // ask user for website
       cin.ignore();  // ignore the newline on the input stream
      cin.get( Awebsite, LENGTH );  // store input in temporary variables
      temp.setWebsite( Awebsite );  // set website
      // set file position pointer and write information to file
      fRef.seekp( ( temp.getRecordNumber() ) * sizeof( EMailObjs ) );
      fRef.write( reinterpret_cast< char * > ( &temp ), sizeof( EMailObjs ) );
  } // end if
   else
     cerr << "Cannot update. The record is empty.\n";
} // end function updateRecord
Nice additional info, but if you read your original post, and read your last comment, you'll notice there isn't a question.

What exactly is your question?
I am having trouble writing the code, and would like an example so I can modify these functions.
same as axter said, lot's of (useful?) information, but where should we start

>> "would like an example"

?? an example for what excactly?

try to be more specific ;)

I made changes in class EMailList:

class EMailList
{
public:
       EMailList(const string& strFileName = "c:\\names.dat", int maxSize = 100)
               : m_strFileName(strFileName), m_maxSize(maxSize), m_loaded(false) {}
       virtual ~EMailList() { for (int i = 0; i < m_pObjs.size(); ++i) delete m_pObjs[i]; }

       EMailObjs* createEMailObj(int rec, const string& name, const string& mailaddr,
                                              const string& webaddr)
       {  if (rec < 0 || rec >= m_maxSize) return NULL; // invalid rec
          if (rec < m_pObjs.size() && 
              m_pObjs[rec] != NULL) return NULL;  // rec already used
          for (int i = m_pObjs.size(); i < rec; ++i)
                m_pObjs.push_back(NULL);   // add NULL pointers between if not contigous
          m_pObjs.push_back(new EMailObjs(rec, name, mailaddr, webaddr));
          return m_pObjs[rec];
       }
       EMailObjs* getEMailObj(int rec)
       {   if (rec < 0 || rec >= m_pObjs.size() ) return NULL; // invalid rec
            return m_pObjs[rec];
       }
       bool loadEMailObjs(  );
       void listEMailObjs( );
       bool removeEmailObjs(int rec);
       bool store(int rec);
       //...

private:
      string             m_strFileName;
      fstream            m_file;
      int                m_maxSize;
      vector<EMailObjs*> m_pObjs;
      bool               m_loaded;
};

// emaillist.cpp

// function that loads tools in file
bool EMailList::loadEMailObjs(  )
{
   if (m_loaded)
       return true;

   m_file.open(m_strFileName.c_str(), ios::out | ios::binary);
   if (m_file.fail())
       return false;

   EMailObjs temp;
   // continue until 100 EMailObjs are loaded or end of file reached
   for ( int count = 0; count < 100 && !m_file.eof(); ++count )
   {
       // set file position pointer and begin reading
      m_file.seekg( count * sizeof( EMailObjs ) );      
      m_file.read( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );
      if (m_file.fail())
          return false;

      if ( temp.getRecordNumber() >= 0 && temp.getRecordNumber() < 100 ) {
          createEMailObj(temp.getRecordNumber(),
                         temp.getName(),
                         temp.getEmailAddress(),
                         temp.getWebsite());
      } // endif
   } // end for

   return m_loaded = true;
} // end function loadEMailObjs

// function that lists tools in file
void EMailList::listEMailObjs( )
{
   EMailObjs* pTemp;
   // display column headings
   cout << '\n' << setw( 3 )  << " " << left
        << setw( 12 ) << "Name" << left
          << setw( 20 ) << "EMail" << left
          << setw( 20 ) << "Website" << left
        << '\n';
   // continue until 100 EMailObjss are displayed or end of file reached
   for ( int count = 0; count < m_pObjs.size(); ++count ) {
       pTemp = m_pObjs[count];
       if (pTemp != NULL)
       {
              // if pTemp is valid, display EMailObjs information
              cout << setw( 2 ) << pTemp->getRecordNumber() << " " 
              << left << setw( 12 ) << pTemp->getName().data()
              << left << setw( 20 ) << pTemp->getEmailAddress().data()
                << left << setw( 20 ) << pTemp->getWebsite().data() << '\n';
       } // end if
   } // end for
} // end function listEMailObjs


// function that lists tools in file
bool EMailList::store( int rec)
{
   EMailObjs* pTemp;
   if (!m_loaded || (pTemp = getEMailObj(rec)) == NULL)
       return false;
   m_file.seekp( ( rec ) * sizeof( EMailObjs ) );
   m_file.write( reinterpret_cast< char * > ( pTemp ), sizeof( EMailObjs ) );
   return !m_file.fail();
}

Then i added to class UserInterface:

// userinterface.h

// forward declaration
class EMailList;

class UserInterface{
public:
    void initializeFile( fstream & );
    int display();
    // function prototypes for managing the random file
    void inputData( fstream & );
    void listEMailObjs( fstream & );
    void updateRecord( fstream & );
    void insertEMailObj( EMailList& list);
    void insertRecord( fstream &);
    void deleteRecord( fstream & );
    int instructions( );

    void insertEMailObj( EMailList& list);    // ask for data and insert to list

    };


// userinterface.cpp

// function to insert a EMailObjs's information
void UserInterface::insertEMailObj( EMailList& list ){
   EMailObjs* pTemp;
   int number;
     char Aname[LENGTH];              
     char Aemail[LENGTH];    
     char Awebsite[LENGTH];
   // ask user what part to update
   cout << "Enter the record number for insertion: ";
   cin >> number;

   pTemp = list.getEMailObj(number);
   if (pTemp == NULL)
   {
      cout << "Enter the new name: "; // ask user for new name

      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aname, LENGTH );   // set new name
      cout << "Enter the new email address: "; // ask user for email address
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aemail, LENGTH );   // store EMail in temporary variable
      cout << "Enter the new website: ";  // ask user for website
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Awebsite, LENGTH );  // store input in temporary variables

      list.createEMailObj(number, Aname, Aemail, Awebsite);
      list.store(number);
  } // end if
   else
      cerr << "Cannot insert. The record contains information.\n";
} // end function insertEMailObj

int UserInterface::display(){
     int choice;
     char response;
   // file stream used for input and output
   fstream file( "C:\\names.dat", ios::in | ios::out );
   // terminate program if file cannot be opened
   if ( !file ) {
      cerr << "File could not be opened.\n";
      exit( EXIT_FAILURE );
   } // end if
   // ask user if new file should be made
   cout << "Should the file be initialized (Y or N): ";
   cin >> response;  
   // test if users response was valid
   while ( toupper( response ) != 'Y' && toupper( response ) != 'N' ) {
      cout << "Invalid response. Enter Y or N: ";
      cin >> response;
   } // end while
   // initialize file if user says too
   if ( toupper( response ) == 'Y' ) {
      initializeFile( file );
      inputData( file );
   } // end if
   file.close();

   EMailList list("C:\\names.dat", 100);

   // perform user instructions until 5 is entered
   while ( ( choice = instructions() ) != 5 ) {

       list.loadEMailObjs();
       switch (choice)   {
        case 1:     list.listEMailObjs(); break;
        case 2:     updateRecord(file); break;
        case 3:     insertEMailObj(list);  break;
        case 4:     deleteRecord(file); break;
        default:     cout<< "Error"; break;
        }
      file.clear();    // reset eof indicator
   } // end while    file.close(); // close input/output file
   return 0;
}


With that you should be able, to add entries and list them.

Todo:

     UserInterface::updateEMailObj(EMailList& list);
     UserInterface::deleteEMailObj(EMailList& list);

     // ...


Regards, Alex


I added the updateRecord function to the EMailList class, and changed EMailObjs temp to EMailList temp.  The function is working if I select a record number that already has data.  But if I select a record that is empty, it should return an error message and that is not working.  I think it is because it is getting the record number from the EMailObjs class instead of from the vector in the EMailList class.  How do I change the code to fix this?  Here is the modified EMailList class:

#ifndef EMAILLIST_H
#define EMAILLIST_H
#include <iostream>
#include <vector>
using namespace std;
#include "EMailObjs.h"

class EMailList: public EMailObjs{
public:
       EMailList(const string& strFileName = "c:\\names.dat", int maxSize = 100)
               : m_strFileName(strFileName), m_maxSize(maxSize) {}
       virtual ~EMailList() { for (int i = 0; i < m_pObjs.size(); ++i) delete m_pObjs[i]; }

       EMailObjs* createEmailObj(int rec, const string& name, const string& mailaddr,
                                              const string& webaddr)
       {  if (rec < 0 || rec >= m_maxSize) return NULL; // invalid rec
          if (rec >= m_pObjs.size() && 
              m_pObjs[rec] != NULL) return NULL;  // rec already used
          for (int i = m_pObjs.size(); i < rec; ++i)
                m_pObjs.push_back(NULL);   // add NULL pointers between if not contigous
          m_pObjs.push_back(new EMailObjs(rec, name, mailaddr, webaddr));
          return m_pObjs[rec];
       }
       EMailObjs* getEmailObj(int rec)
       {   if (rec < 0 || rec >= m_pObjs.size() ) return NULL; // invalid rec
            return m_pObjs[rec];
       }
       bool removeEmailObjs(int rec);

         void updateRecord( fstream & );
            
private:
      string             m_strFileName;
      int                m_maxSize;
      vector<EMailObjs*> m_pObjs;
};

void updateRecord( fstream &fRef )
{
   EMailList temp;
   int number;
      char Aname[LENGTH];                  
      char Aemail[LENGTH];      
      char Awebsite[LENGTH];

   // ask user what part to update
   cout << "Enter the record number for update: ";
   cin >> number;

   // set file positions pointer to correct EMailObjs
   fRef.seekg( number * sizeof( EMailObjs ) );

   // read EMailObjs information
   fRef.read( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );

   // display EMailObjs information if partNumber is not -1
   if ( temp.getRecordNumber() != -1 ) {
      cout << '\n' << setw( 3 ) << " " << left
        << setw( 12 ) << "Name" << left
            << setw( 20 ) << "EMail" << left
            << setw( 20 ) << "Website" << left
        << '\n';

         cout << setw( 2 ) << temp.getRecordNumber() << " " 
              << left << setw( 12 ) << temp.getName().data()
              << left << setw( 20 ) << temp.getEmailAddress().data()
                    << left << setw( 20 ) << temp.getWebsite().data()
              << '\n';
        cout << "Enter the new name: "; // ask user for new name

      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aname, LENGTH );   // set new name
      temp.setName( Aname );  
      cout << "Enter the new email address: "; // ask user for email address
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aemail, LENGTH );   // store EMail in temporary variable
      temp.setEmailAddress( Aemail );  // set EMail address
      cout << "Enter the new website: ";  // ask user for website
        cin.ignore();  // ignore the newline on the input stream
      cin.get( Awebsite, LENGTH );  // store input in temporary variables
      temp.setWebsite( Awebsite );  // set website

      // set file position pointer and write information to file
      fRef.seekp( ( temp.getRecordNumber() ) * sizeof( EMailObjs ) );
      fRef.write( reinterpret_cast< char * > ( &temp ), sizeof( EMailObjs ) );
   
   } // end if
   else
      cerr << "Cannot update. The record is empty.\n";

} // end function updateRecord

#endif
>> if (rec >= m_pObjs.size() &&

That statement is wrong. I changed it in my last post:

    if (rec < m_pObjs.size() && ...

Generally, you should have exactly one EMailList object that manages all persistent EMailObjs. The UserInterface instance should do all user IO and could have the - one and only - EMailList instance as private member. Then,  you don't have to pass it as argument as i did with  'UserInterface::insertEMailObj'. So, in main() you create a EMailList and a UserInterface passing the reference of the EMaillList to the constructor of UserInterface. Move all loading and storing functions to EMailList and all display and dialog functions to UserInterface. The fstream instance should be a member of EMailList as an IO class shouldn't  do file jhand
Thanks Alex- I answered ikework's post before I got your post.  I am still having some problems with the program.  Items are saved during the current session, but the data is not being saved to the file.  When you start another session, the file is empty.  I added the updateEmailObj, but it is not overwriting the previous data.  deleteEmailObj is not working either.  BTW, I also got rid of the option to initialize the file.  Here is the updated code:

//main.cpp
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>

#include "EMailObjs.h"
#include "UserInterface.h"
#include "EMailList.h"

using namespace std;

int main()
{
   UserInterface test;
   test.display();
   return 0;
} // end main
///////////////////////////////////////////////////////////////////////////////////////
//EMailObjs.h
#ifndef EMAILOBJS_H
#define EMAILOBJS_H
#include <iostream>
using namespace std;

const int LENGTH = 50;

class EMailObjs{
public:
      EMailObjs(int= -1, string = "", string = "", string = "");  //default constructor
      void setRecordNumber( int );
    int getRecordNumber() const;
      void setName(string);
      string getName()const;
      void setEmailAddress(string);
      string getEmailAddress()const;
      void setWebsite(string);
      string getWebsite()const;
private:
      int recordNumber;
      char name[LENGTH];                  // name of person or company
      char email[LENGTH];                  // email address
      char website[LENGTH];            // website address
};
#endif
//EMailObjs.cpp
#include <iostream>
#include <cstring>
using namespace std;
#include "EMailObjs.h"

EMailObjs::EMailObjs(int recordNumberValue, string nameValue, string emailValue, string websiteValue){
      setRecordNumber( recordNumberValue );
      setName(nameValue);
      setEmailAddress(emailValue);
      setWebsite(websiteValue);
}

void EMailObjs::setRecordNumber( int recordNumberValue ){
   recordNumber = recordNumberValue;
}

int EMailObjs::getRecordNumber() const{
   return recordNumber;
}

void EMailObjs::setName(string nameString){
      const char *nameValue = nameString.data();
      int length = strlen(nameValue);
      length = (length < 50 ? length : 49);
      strncpy(name, nameValue, length);
      name[length] = '\0';
}

string EMailObjs::getName()const{
      return name;
}

void EMailObjs::setEmailAddress(string emailString){
      const char *emailValue = emailString.data();
      int length = strlen(emailValue);
      length = (length < 50 ? length : 49);
      strncpy(email, emailValue, length);
      email[length] = '\0';
}

string EMailObjs::getEmailAddress()const{
      return email;
}

void EMailObjs::setWebsite(string websiteString){
      const char *websiteValue = websiteString.data();
      int length = strlen(websiteValue);
      length = (length < 50 ? length : 49);
      strncpy(website, websiteValue, length);
      website[length] = '\0';
}

string EMailObjs::getWebsite()const{
      return website;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//EMailList.h
#ifndef EMAILLIST_H
#define EMAILLIST_H
#include <iostream>
#include <vector>
#include "EMailObjs.h"
using namespace std;

class EMailList{
public:
       EMailList(const string& strFileName = "c:\\names.dat", int maxSize = 100)
               : m_strFileName(strFileName), m_maxSize(maxSize), m_loaded(false) {}
       virtual ~EMailList() { for (int i = 0; i < m_pObjs.size(); ++i) delete m_pObjs[i]; }

       EMailObjs* createEMailObj(int rec, const string& name, const string& mailaddr,
                                              const string& webaddr)
       {  if (rec < 0 || rec >= m_maxSize) return NULL; // invalid rec
          if (rec < m_pObjs.size() && 
              m_pObjs[rec] != NULL) return NULL;  // rec already used
          for (int i = m_pObjs.size(); i < rec; ++i)
                m_pObjs.push_back(NULL);   // add NULL pointers between if not contigous
          m_pObjs.push_back(new EMailObjs(rec, name, mailaddr, webaddr));
          return m_pObjs[rec];
       }
       EMailObjs* getEMailObj(int rec)
       {   if (rec < 0 || rec >= m_pObjs.size() ) return NULL; // invalid rec
            return m_pObjs[rec];
       }
       bool loadEMailObjs( );
       void listEMailObjs( );
       bool store(int rec);
       
private:
      string             m_strFileName;
      fstream            m_file;
      int                m_maxSize;
      vector<EMailObjs*> m_pObjs;
      bool               m_loaded;
};
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//EMailList.cpp
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include "UserInterface.h"
#include "EMailObjs.h"
#include "EMailList.h"
using namespace std;

// function that loads tools in file
bool EMailList::loadEMailObjs(  ){
   if (m_loaded)
       return true;

   m_file.open(m_strFileName.c_str(), ios::out | ios::binary);
   if (m_file.fail())
       return false;

   EMailObjs temp;
   // continue until 100 EMailObjs are loaded or end of file reached
   for ( int count = 0; count < 100 && !m_file.eof(); ++count )
   {
       // set file position pointer and begin reading
      m_file.seekg( count * sizeof( EMailObjs ) );      
      m_file.read( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );
      if (m_file.fail())
          return false;

      if ( temp.getRecordNumber() >= 0 && temp.getRecordNumber() < 100 ) {
          createEMailObj(temp.getRecordNumber(),
                         temp.getName(),
                         temp.getEmailAddress(),
                         temp.getWebsite());
      } // endif
   } // end for

   return m_loaded = true;
} // end function loadEMailObjs

// function that lists records in file
void EMailList::listEMailObjs( ){
   EMailObjs* pTemp;
   // display column headings
   cout << '\n' << setw( 3 )  << " " << left
        << setw( 12 ) << "Name" << left
          << setw( 20 ) << "EMail" << left
          << setw( 20 ) << "Website" << left
        << '\n';
   // continue until 100 EMailObjs are displayed or end of file reached
   for ( int count = 0; count < m_pObjs.size(); ++count ) {
       pTemp = m_pObjs[count];
       if (pTemp != NULL)
       {
              // if pTemp is valid, display EMailObjs information
              cout << setw( 2 ) << pTemp->getRecordNumber() << " " 
              << left << setw( 12 ) << pTemp->getName().data()
              << left << setw( 20 ) << pTemp->getEmailAddress().data()
                << left << setw( 20 ) << pTemp->getWebsite().data() << '\n';
       } // end if
   } // end for
} // end function listEMailObjs

// function that lists records in file
bool EMailList::store( int rec){
   EMailObjs* pTemp;
   if (!m_loaded || (pTemp = getEMailObj(rec)) == NULL)
       return false;
   m_file.seekp( ( rec ) * sizeof( EMailObjs ) );
   m_file.write( reinterpret_cast< char * > ( pTemp ), sizeof( EMailObjs ) );
   return !m_file.fail();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//UserInterface.h
#ifndef USERINTERFACE_H
#define USERINTERFACE_H

#include <iostream>
#include "EMailList.h"

using namespace std;

class EMailList;

class UserInterface{
public:
int display();
void updateEMailObj(EMailList& list);
void insertEMailObj (EMailList& list);  
void deleteEMailObj(fstream &);
int instructions( );
};
#endif
/////////////////////////////////////////////////////////////////////////////
//UserInterface.cpp
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>

#include "UserInterface.h"
#include "EMailObjs.h"
#include "EMailList.h"

using namespace std;

// function to insert a EMailObjs's information
void UserInterface::insertEMailObj( EMailList& list ){
   EMailObjs* pTemp;
   int number;
     char Aname[LENGTH];              
     char Aemail[LENGTH];    
     char Awebsite[LENGTH];
   cout << "Enter the record number for insertion: ";
   cin >> number;

   pTemp = list.getEMailObj(number);
   if (pTemp == NULL)
   {
      cout << "Enter the new name: "; // ask user for new name
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aname, LENGTH );   // set new name
      cout << "Enter the new email address: "; // ask user for email address
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aemail, LENGTH );   // store EMail in temporary variable
      cout << "Enter the new website: ";  // ask user for website
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Awebsite, LENGTH );  // store input in temporary variables

      list.createEMailObj(number, Aname, Aemail, Awebsite);
      list.store(number);
  } // end if
   else
      cerr << "Cannot insert. The record contains information.\n";
} // end function insertEMailObj

int UserInterface::display(){
      int choice;
      
   // file stream used for input and output
   fstream file( "C:\\names.dat", ios::in | ios::out );
     
   // terminate program if file cannot be opened
   if ( !file ) {
      cerr << "File could not be opened.\n";
      exit( EXIT_FAILURE );
   } // end if

   EMailList list("C:\\names.dat", 100);
   
   // perform user instructions until 5 is entered
   while ( ( choice = instructions() ) != 5 ) {
         list.loadEMailObjs();
       switch (choice){
         case 1:      list.listEMailObjs( );
                  break;
         case 2:      updateEMailObj(list);
               break;
         case 3:      insertEMailObj(list);
               break;
         case 4:      deleteEMailObj(file);
               break;
         default:      cout<< "Error";
               break;
         }
      file.clear();    // reset eof indicator
      } // end while

   file.close(); // close input/output file
   return 0;
}

// function that decides what choice user selected
int UserInterface::instructions( ){
   int choice;
   // ask user to enter a choice
   cout << "\nEnter a choice:\n" <<
                  "1  List all records.\n" <<
                  "2  Change record.\n" <<
                  "3  Add a record.\n" <<
                  "4  Delete a record.\n" <<
                  "5  Quit.\n";
   // ask user for choice until a valid choice is entered
   do {
      cout << "? ";
      cin >> choice;
   } while ( choice < 1 || choice > 5 );
   return choice; // return user choice
} // end function instructions

// function to update a EMailObjs's information
void UserInterface::updateEMailObj( EMailList& list ){
   EMailObjs* pTemp;
   int number;
      char Aname[LENGTH];                  
      char Aemail[LENGTH];      
      char Awebsite[LENGTH];

   cout << "Enter the record number for update: ";
   cin >> number;

   pTemp = list.getEMailObj(number);
   if (pTemp != NULL)
   {      cout << '\n' << setw( 3 ) << " " << left
        << setw( 12 ) << "Name" << left
            << setw( 20 ) << "EMail" << left
            << setw( 20 ) << "Website" << left
        << '\n';
         cout << setw( 2 ) << pTemp->getRecordNumber() << " " 
              << left << setw( 12 ) << pTemp->getName().data()
              << left << setw( 20 ) << pTemp->getEmailAddress().data()
                    << left << setw( 20 ) << pTemp->getWebsite().data()
              << '\n';
      cout << "Enter the new name: "; // ask user for new name
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aname, LENGTH );   // set new name
      cout << "Enter the new email address: "; // ask user for email address
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Aemail, LENGTH );   // store EMail in temporary variable
      cout << "Enter the new website: ";  // ask user for website
      cin.ignore();  // ignore the newline on the input stream
      cin.get( Awebsite, LENGTH );  // store input in temporary variables

      list.createEMailObj(number, Aname, Aemail, Awebsite);
      list.store(number);
  } // end if
   else
      cerr << "Cannot update. The record is empty.\n";
} // end function updateRecord

// function to delete a record
void UserInterface::deleteEMailObj( fstream &fRef ){
   EMailObjs blankItem;
   EMailObjs temp;
   int number;

   cout << "Enter the record number for deletion: ";
   cin >> number;

   // set file position pointer and read information from file
   fRef.seekg( number * sizeof( EMailObjs ) );
   fRef.read( reinterpret_cast< char * >( &temp ), sizeof( EMailObjs ) );

   // if record contains data, set record to an empty EMailObjs object
   if ( temp.getRecordNumber() != -1 ) {
      fRef.seekp( number * sizeof( EMailObjs ) );
      fRef.write( reinterpret_cast< char * >( &blankItem ), sizeof( EMailObjs ) );
      cout << "Record deleted.\n";
   } // end if
   else
        cerr << "Cannot delete. The record is empty.\n";
} // end function deleteRecord
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

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
Thanks a bunch Alex- great code.  I have learned a lot.  I am going to open one more question to add a search function, so look for it if you would like some more points.