The code shown in listings 1-3 is available on your distribution disks as PERSON.H, PERSON.CPP, and DMTEST.CPP.
// person.h : Defines the class interfaces for CPerson, CPersonList.
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1991 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and Microsoft
// QuickHelp documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#ifndef __PERSON_H__
#define __PERSON_H__
#ifdef _DOS
#include <afx.h>
#else
#include <afxwin.h>
#endif
#include <afxcoll.h>
/////////////////////////////////////////////////////////////////////////////
// class CPerson:
// Represents one person in the phone database. This class is derived from
// CObject (mostly to get access to the serialization protocol).
class CPerson : public CObject
{
DECLARE_SERIAL( CPerson );
public:
//Construction
// For serializable classes, declare a constructor with no arguments.
CPerson()
{ m_modTime = CTime::GetCurrentTime(); }
CPerson( const CPerson& a );
// For our convenience, also declare a constructor with arguments.
CPerson( const char* pszLastName,
const char* pszFirstName,
const char* pszPhoneNum );
//Attributes
// Member functions to modify the protected member variables.
void SetLastName( const char* pszName )
{ ASSERT_VALID( this );
ASSERT( pszName != NULL);
m_LastName = pszName;
m_modTime = CTime::GetCurrentTime(); }
const CString& GetLastName() const
{ ASSERT_VALID( this );
return m_LastName; }
void SetFirstName( const char* pszName )
{ ASSERT_VALID( this );
ASSERT( pszName != NULL );
m_FirstName = pszName;
m_modTime = CTime::GetCurrentTime(); }
const CString& GetFirstName() const
{ ASSERT_VALID( this );
return m_FirstName; }
void SetPhoneNumber( const char* pszNumber )
{ ASSERT_VALID( this );
ASSERT( pszNumber != NULL );
m_PhoneNumber = pszNumber;
m_modTime = CTime::GetCurrentTime(); }
const CString& GetPhoneNumber() const
{ ASSERT_VALID( this );
return m_PhoneNumber; }
const CTime GetModTime() const
{ ASSERT_VALID( this );
return m_modTime; }
//Operations
CPerson& operator=( const CPerson& b );
//Implementation
protected:
// Member variables that hold data for person
CString m_LastName;
CString m_FirstName;
CString m_PhoneNumber;
CTime m_modTime;
public:
// Override the Serialize function
virtual void Serialize( CArchive& archive );
#ifdef _DEBUG
// Override Dump for debugging support
virtual void Dump( CDumpContext& dc ) const;
virtual void AssertValid() const;
#endif
};
/////////////////////////////////////////////////////////////////////////////
// class CPersonList:
// This represents a list of all persons in a phone database. This class is
// derived from CObList, a list of pointers to CObject-type objects.
class CPersonList : public CObList
{
DECLARE_SERIAL( CPersonList )
public:
//Construction
CPersonList()
{ m_bIsDirty = FALSE; }
// Add new functions
CPersonList* FindPerson( const char * szTarget );
// SetDirty/GetDirty
// Mark the person list as "dirty" (meaning "modified"). This flag can be
// checked later to see if the database needs to be saved.
//
void SetDirty( BOOL bDirty )
{ ASSERT_VALID( this );
m_bIsDirty = bDirty; }
BOOL GetDirty()
{ ASSERT_VALID( this );
return m_bIsDirty; }
// Delete All will delete the Person objects as well as the pointers.
void DeleteAll();
protected:
BOOL m_bIsDirty;
};
/////////////////////////////////////////////////////////////////////////////
#endif // __PERSON_H__
// person.cpp : Defines the class behaviors for CPerson, CPersonList.
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1991 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and Microsoft
// QuickHelp documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "person.h"
#include <string.h>
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////
//
// Call 'IMPLEMENT_SERIAL' macro for all the
// classes declared in person.h
IMPLEMENT_SERIAL( CPerson, CObject, 0 )
IMPLEMENT_SERIAL( CPersonList, CObList, 0 )
//////////////////////////////////////////////
// Define member functions for classes
// declared in person.h
//
//////////////////////////////////////////////
// CPerson::CPerson
// Copy Constructor for CPerson class
//
CPerson::CPerson( const CPerson& a )
{
m_LastName = a.m_LastName;
m_FirstName = a.m_FirstName;
m_PhoneNumber = a.m_PhoneNumber;
m_modTime = a.m_modTime;
}
//////////////////////////////////////////////
// CPerson::CPerson
// Memberwise Constructor for CPerson class
//
CPerson::CPerson( const char* pszLastName,
const char* pszFirstName,
const char* pszPhoneNum )
{
ASSERT_VALID( this );
m_LastName = pszLastName;
m_FirstName = pszFirstName;
m_PhoneNumber = pszPhoneNum;
m_modTime = CTime::GetCurrentTime();
}
//////////////////////////////////////////////
// CPerson::operator=
// Overloaded operator= to perform assignments.
//
CPerson& CPerson::operator=( const CPerson& b )
{
ASSERT_VALID( this );
ASSERT_VALID( &b );
m_LastName = b.m_LastName;
m_FirstName = b.m_FirstName;
m_PhoneNumber = b.m_PhoneNumber;
m_modTime = b.m_modTime;
return *this;
}
///////////////////////////////////////////////
// CPerson::Dump
// Write the contents of the object to a
// diagnostic context
//
// The overloaded '<<' operator does all the hard work
//
#ifdef _DEBUG
void CPerson::Dump( CDumpContext& dc ) const
{
ASSERT_VALID( this );
// Call base class function first
CObject::Dump( dc );
// Now dump data for this class
dc << "\n"
<< "Last Name: " << m_LastName << "\n"
<< "First Name: " << m_FirstName << "\n"
<< "Phone #: " << m_PhoneNumber << "\n"
<< "Modification date: " << m_modTime << "\n";
}
void CPerson::AssertValid() const
{
}
#endif
/////////////////////////////////////////////
// CPerson::Serialize
// Read or write the contents of the object
// to an archive
//
void CPerson::Serialize( CArchive& archive )
{
ASSERT_VALID( this );
// Call base class function first
CObject::Serialize( archive );
// Now dump data for this class
if ( archive.IsStoring() )
{
archive << m_LastName << m_FirstName << m_PhoneNumber
<< m_modTime;
}
else
{
archive >> m_LastName >> m_FirstName >> m_PhoneNumber
>> m_modTime;
}
}
//////////////////////////////////////////////////////////////////////////////
// CPersonList
// We inherit most of the functionality from CObList. These are only
// functions that we added to form our own list type.
//
//////////////////////////////////////////////
// CPersonList::FindPerson
//
CPersonList* CPersonList::FindPerson( const char * szTarget )
{
ASSERT_VALID( this );
CPersonList* pNewList = new CPersonList;
CPerson* pNext = NULL;
// Start at front of list
POSITION pos = GetHeadPosition();
// Iterate over whole list
while( pos != NULL )
{
// Get next element (note cast)
pNext = (CPerson*)GetNext(pos);
// Add current element to new list if it matches
if ( _strnicmp( pNext -> GetLastName(), szTarget, strlen( szTarget ) )
== 0 )
pNewList -> AddTail(pNext);
}
if ( pNewList -> IsEmpty() )
{
delete pNewList;
pNewList = NULL;
}
return pNewList;
}
//////////////////////////////////////////
// CPersonList::DeleteAll
// This will delete the objects in the list as the pointers.
//
void CPersonList::DeleteAll()
{
ASSERT_VALID( this );
POSITION pos = GetHeadPosition();
while( pos != NULL )
{
delete GetNext(pos);
}
RemoveAll();
}
// dmtest.cpp : A program to test the CPerson and CPersonList classes.
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1991 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and Microsoft
// QuickHelp documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "person.h"
// Function prototypes.
CPersonList* MakeDataBase();
CFile* OpenForReading( const CString& rFileName );
CFile* OpenForWriting( const CString& rFileName );
CPersonList* ReadDataBase( CFile* pFile );
BOOL WriteDataBase( CFile* pFile, CPersonList* pDataBase );
void TestFindPerson( CPersonList* pDataBase );
void ListDataBase( CPersonList* db );
/////////////////////////////////////////////////////////////////////////////
void main()
{
const char szFileName[] = "tutorial.dat";
#ifdef _DEBUG
// Prepare for display of search results
const int nDumpChildren = 1;
afxDump.SetDepth( nDumpChildren );
#endif
printf( "Create a person list and fill it with persons\n" );
CPersonList* pDataBase = MakeDataBase();
printf( "Serialize the person list\n" );
CFile* pFile; // Declare a file object
TRY
{
// Could throw a file exception if can't open file
pFile = OpenForWriting( szFileName );
// Could throw an archive exception if can't create
WriteDataBase( pFile, pDataBase );
}
CATCH( CFileException, theException )
{
printf( "Unable to open file for writing\n" );
exit( -1 );
}
AND_CATCH( CArchiveException, theException )
{
printf( "Unable to save the database\n" );
pFile -> Close(); // Close up
delete pFile;
exit( -1 );
}
// No exceptions, so close up
pFile -> Close();
delete pFile;
ListDataBase( pDataBase );
printf( "Delete the list and all its elements\n" );
pDataBase -> DeleteAll();
ListDataBase( pDataBase );
delete pDataBase;
printf( "Deserialize the data from disk into a new list\n" );
CPersonList* pDataBase2; // Create a new, empty list
TRY
{
// Could throw a file exception if can't open file
pFile = OpenForReading( szFileName );
// Could throw an archive exception if can't create
pDataBase2 = ReadDataBase( pFile );
}
CATCH( CFileException, theException )
{
printf( "Unable to open file for reading database\n" );
exit( -1 );
}
AND_CATCH( CArchiveException, theException )
{
printf( "Unable to read the database\n" );
pFile -> Close(); // Close up before exiting
delete pFile;
exit( -1 );
}
// No exceptions, so close up
pFile -> Close();
delete pFile;
ListDataBase( pDataBase2 );
printf( "Test the FindPerson function\n" );
if ( pDataBase2 != NULL )
TestFindPerson( pDataBase2 );
printf( "Delete the list and all its elements\n" );
pDataBase2 -> DeleteAll();
delete pDataBase2;
TRACE( "End of program\n" );
}
// MakeDataBase - Create a database and add some persons
//
CPersonList* MakeDataBase()
{
TRACE( " Make a new person list on the heap\n" );
CPersonList* pDataBase = new CPersonList;
TRACE( " Add several new persons to the list\n" );
CPerson* pNewPerson1 = new CPerson( "Smith", "Mary", "435-8159" );
pDataBase -> AddHead( pNewPerson1 );
CPerson* pNewPerson2 = new CPerson( "Smith", "Al", "435-4505" );
pDataBase -> AddHead( pNewPerson2 );
CPerson* pNewPerson3 = new CPerson( "Jones", "Steve", "344-9865" );
pDataBase -> AddHead( pNewPerson3 );
CPerson* pNewPerson4 = new CPerson( "Hart", "Mary", "287-0987" );
pDataBase -> AddHead( pNewPerson4 );
CPerson* pNewPerson5 = new CPerson( "Meyers", "Brian", "236-1234" );
pDataBase -> AddHead( pNewPerson5 );
TRACE( " Return the completed database to main\n" );
return pDataBase;
}
// OpenForReading - open a file for reading
//
CFile* OpenForReading( const CString& rFileName )
{
CFile* pFile = new CFile;
CFileException* theException = new CFileException;
if ( !pFile -> Open( rFileName, CFile::modeRead, theException ) )
{
delete pFile;
TRACE( " Threw file exception in OpenForReading\n" );
THROW( theException );
}
delete theException;
// Exit here if no exceptions
return pFile;
}
// OpenForWriting - open a file for writing
//
CFile* OpenForWriting( const CString& rFileName )
{
CFile* pFile = new CFile;
CFileStatus status;
UINT nAccess = CFile::modeWrite;
// GetStatus will return TRUE if file exists,
// or FALSE if it doesn't exist
if ( !CFile::GetStatus( rFileName, status ) )
nAccess |= CFile::modeCreate;
CFileException* theException = new CFileException;
if ( !pFile -> Open( rFileName, nAccess, theException ) )
{
delete pFile;
TRACE( " Threw a file exception in OpenForWriting\n" );
THROW( theException );
}
delete theException;
// Exit here if no errors or exceptions
TRACE( " Opened file for writing OK\n" );
return pFile;
}
// ReadDataBase - read data into a person list
//
CPersonList* ReadDataBase( CFile* pFile )
{
CPersonList* pNewDataBase = NULL;
// Create an archive from pFile for reading
CArchive archive( pFile, CArchive::load );
TRY
{
// and deserialize the new data base from the archive
archive > pNewDataBase;
}
CATCH( CArchiveException, theException )
{
TRACE( " Caught an archive exception in ReadDataBase\n" );
#ifdef _DEBUG
theException -> Dump( afxDump );
#endif
archive.Close();
// If we got part of the database then delete it so we don't
// have any Memory leaks
if ( pNewDataBase != NULL )
{
pNewDataBase -> DeleteAll();
delete pNewDataBase;
}
THROW_LAST();
}
// Exit here if no errors or exceptions
archive.Close();
return pNewDataBase;
}
// WriteDataBase - write data from a person list to disk
//
BOOL WriteDataBase( CFile* pFile, CPersonList* pDataBase )
{
// Create an archive from pFile for writing
CArchive archive( pFile, CArchive::store );
TRY
{
// and serialize the data base to the archive
archive < pDataBase;
}
CATCH( CArchiveException, theException )
{
TRACE( " Caught an archive exception in WriteDataBase\n" );
#ifdef _DEBUG
theException -> Dump( afxDump );
#endif
archive.Close();
THROW_LAST();
}
// Exit here if no errors or exceptions
archive.Close();
return TRUE;
}
// TestFindPerson - test CPersonList::FindPerson
//
void TestFindPerson( CPersonList* pDataBase )
{
printf( " Looking for the name Banipuli\n" );
CPersonList* pFound = pDataBase -> FindPerson( "Banipuli" );
if ( pFound -> IsEmpty() )
{
printf( " No matching persons\n" );
}
else
{
printf( " Found matching persons\n" );
#ifdef _DEBUG
pFound -> Dump( afxDump );
#endif
}
delete pFound;
printf( " Looking for the name Smith\n" );
pFound = pDataBase -> FindPerson( "Smith" );
if ( pFound -> IsEmpty() )
{
printf( " No matching persons\n" );
}
else
{
printf( " Found matching persons\n" );
#ifdef _DEBUG
pFound -> Dump( afxDump );
#endif
}
// Don't DeleteAll the found list since it
// shares CPerson objects with dataBase
delete pFound; // Deletes only the list object
}
void ListDataBase( CPersonList* db )
{
CPerson* pCurrent;
POSITION pos;
if ( db -> GetCount() == 0 )
printf( " List is Empty\n" );
else
{
printf( " List contains:\n" );
pos = db -> GetHeadPosition();
while ( pos != NULL )
{
pCurrent = (CPerson*)db -> GetNext( pos );
printf( "\t%s, %s\t%s\n", (const char*)pCurrent -> GetLastName(),
(const char*)pCurrent -> GetFirstName(),
(const char*)pCurrent -> GetPhoneNumber() );
}
}
}