Project 2 (Posted 11/03/04)

Due December 7 (Tuesday), 2004 24:00

 

Project Objective

 

Files are accessed sequentially one byte at a time. When a file is a collection of records of fixed size, we may access a given record directly without comparing each byte in searching for a particular record. Such a file is called a random access file. Formats of records depend on applications. The objective of this project is to write a C++ program that generates a random access file for an arbitrary type (class) of records.

 

Project Description:

 

Your program will include a Person class holding general attributes of a person, an Undergrad class holding special attributes of an undergraduate student in addition to the inherited attributes from Person, and a template Database class that handles these two classes (types) of records.

 

To help ease your programming task, the project is divided into three parts. You may implement, debug, and test each part sequentially. Namely, Part I can be completed without completing Part II and Part II can be completed without completing Part III.

 

Part I. The Person Class and the Test Driver

 

1.      The Person class is the base class. It uses the following five attributes: name, SSN (social security number), birthday, birthplace, and address, to identify a person. Create two files person.h and person.cc for defining and implementing this class. Given below is a sample definition of Person. Feel free to add other constructors and methods if needed.

 

#ifndef PERSON

#define PERSON

 

class Person {

public:

Person( ); // default constructor

Person( char*, char*, char*, char*, char* );

~Person( );

 

    void write_to_file( fstream& ) const;

void read_from_file( fstream& );

ostream& pretty_print( ostream& );  // print Person record nicely

istream& read_from_console( istream& );

void get_key(); // read SSN as a key from console

int record_size( ) const; // return the size of the object (i.e., the entire record)

   

bool operator==( const Person& ) const;

// overloaded ==; return true if parameter’s SSN is the same as this->SSN

          friend ostream& operator<<(ostream& out, Person& person) {

               return perrson.pretty_print( out );

         }

         friend istream& operator>>( istream& in, Person& person ) {

              return person.read_from_console( in );

     }

 

protected:

        

         char* name;

         char SSN[9];

         char* birthday; // e.g., in the format of 11/02/04

         char* birthplace;

         char* address;

         const int nLen, bdLen, bpLen, aLen; // feel free to set bounds on these variables

 

private:

     // feel free to add private members if you need them.

     // For example, you could put all the protected data members private, and then create

     // public methods to read from and write to these private members

    };

 

    #endif

 

2.      Sample output:

 

Enter Name: John Doe

Enter SSN: 034456789

Enter Birthday: 11/02/86

Enter Birthplace: Boston, MA

Enter Address: 198 Riverside Street, Lowell, MA 01854

 

Pretty Print Record:

SSN:                      03445678

Name:                    John Doe

Birthday:                 11/02/86

Birthplace:              Boston, MA;

Address:                 198 Riverside Street, Lowell, MA 01854  

 

3.      Sample code:

 

void Person::write_to_file( fstream& out ) const {

     out.write( SSN, 9 );

     out.write( Nme, nLen );

     out.write( Birthday, bdLen );

           out.write( Birthplace, bpLen );

           out.write( Address, aLen );

      }

     To use “read_from_file” in your test driver (i.e., the main() function):

 

      string filename;

      cin >> filename;

      fstream file;

      file.open( filename.c_str() ), ios::in | ios::out | ios::binary );

      // More information on I/O hierarchy classes will be given in Chapter 8

      // Note: If you are using newer version of C++ compiler, replace ios with ios_base

      Person p;

      p.read_from_file( file );

 

 

Part II

 

The Undergrad class derives from the Person class. In addition to the inherited data members, an Undergrad object also contains the following attributes: major, minor, and status (freshman, sophomore, junior, senior). The following is a sample definition of the Undergrad class. Feel free to add additional constructors and members.

 

#ifndef UNDERGRAD

#define UNDERGRAD

 

#include "Person.h"

 

Enum Status { freshman, sophomore, junior, senior };

 

class Undergrad : public Person {

public:

       Undergrad( );

       Undergrad( char*, char*, char*, char*, char*, char*, char*,  Status);

       ~Undergrad( );

 

       void write-to_file( fstream& ) const;

       void read_from_file( fstream& );

       int record_size( ) const;

       ostream& pretty_print( ostream& );  // print Person record nicely

       istream& read_from_console( istream& );

       friend ostream& operator<<(ostream& out, Undergrad& );

   friend istream& operator>>( istream& in, Undergrad& );

 

private:

       char *major;

       char *minor;

       Status status;

       const int majorLen, minorLen;

};

 

#endif

 

Part III

 

The Database class is a template class, which can handle a random access file of Person records as well as a random access file of Undergrad records. A random access file is analogous to an array: Given a key, we can translate it into a relative address using a hash function. Once we have the relative address, we can determine approximately where the record is located in the file, find it quickly, and then access it.

 

Format of the file: The file is in binary. It begins with a header, including necessary information for random accessing a particular record. For example, the header should contain the maximum number of records that can be stored in the file, the size of a record, the size of a key (i.e., SSN), the number of records stored in the file, a location where a record can be stored, etc.

 

The records in a random access file are stored following the file header. The first byte of a record, which is not part of the logical record, holds a status flag whose value is one of the followings:

 

·      T (for “taken”), indicating a record is stored

·      D (for “deleted”), indicating a record was stored but deleted. Note that a deleted record is not physically removed from the file. But a new record can take its location as long as the record has been marked “D”. Also, a deleted record is not available for searching.

·      F (for “free”), indicating a record is never stored.

 

The remaining bytes store the key (SSN) and the rest of the record.

 

Hash function:  We use a simple hashing function as in the textbook, namely, the address of the record with key k is k % M, where M is the maximum number of records in the file. In case of collision, the formula (address+1) % M is used to find the next available address.

 

Methods of the Database class include:

·        add_record: Add a new record into the file

·        find_record: Given a key (SSN), find and print the record in the file

·        delete_record: Given a key, find the record and delete it from the file

·        print_records: Print all the records in the file

 

For an example of a random access file, please read RandomAccessFile.h and RandomAccessFile.cc at ~wang/cs201. Feel free to borrow code from the sample.

 

What to Submit?

 

Submit your source code and Makefile for compiling your program.

 

How will you be graded?

 

The criteria for grading are the same as in Project 1. The most important part is that your program compiles and works properly.