Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

lafore_robert_objectoriented_programming_in_c

.pdf
Скачиваний:
51
Добавлен:
27.03.2023
Размер:
8.94 Mб
Скачать

Object-Oriented Software Development

The use cases determined in the elaboration phase translate into iterations in the construction phase. (See Figure 16.2). In a large project each of these iterations might be handled by a different team of programmers. Each iteration can be developed separately, and sent back to the users to determine changes or refinements. In our small program we don’t need this complexity.

The Header File

The best place to start coding is the .H file, where you define class interfaces, rather than the details of their implementations. As we’ve discussed before, the declarations in the .H file are the public part of the classes, the part that users of these classes see. The function bodies in the

.CPP file are the implementations, which should be invisible to class users.

The creation of the .H file is an intermediate step between design and the nitty-gritty of writing method bodies. Here’s the LANDLORD.H file:

//landlord.h

//header file for landlord.cpp -- contains class declarations, etc.

#pragma warning (disable:4786)

//for set (microsoft only)

#include <iostream>

 

#include <vector>

 

#include <set>

 

#include <string>

 

#include <algorithm>

//for sort()

#include <numeric>

//for accumulate()

using namespace std;

 

//////////////////////////global

methods///////////////////////

void getaLine(string& inStr);

// get line of text

char getaChar();

// get a character

///////////////////////////class tenant/////////////////////////

class tenant

 

 

 

{

 

 

 

private:

 

 

 

string name;

//

tenant’s

name

int aptNumber;

//

tenant’s

apartment number

// other tenant information (phone, etc.) could go here

public:

 

 

tenant(string n, int

aNo);

~tenant();

 

int getAptNumber();

 

// needed for use in

‘set’

friend

bool operator

< (const tenant&, const tenant&);

friend

bool operator

== (const tenant&, const tenant&);

// for

I/O

 

825

16

O D BJECT EVELOPMENT S

OFTWARE - RIENTEDO

826

Chapter 16

friend ostream& operator << (ostream&, const tenant&);

 

 

 

}; // end class tenant

 

///////////////////////class compareTenants/////////////////////

 

class compareTenants //function object -- compares tenants

 

{

 

public:

 

bool operator () (tenant*, tenant*) const;

 

};

 

////////////////////////class tenantList////////////////////////

 

class tenantList

 

{

 

private:

 

// set of pointers to tenants

 

set<tenant*, compareTenants> setPtrsTens;

 

set<tenant*, compareTenants>::iterator iter;

public:

 

~tenantList();

// destructor (deletes tenants)

void insertTenant(tenant*);

// put tenant on list

int getAptNo(string);

// return apartment number

void display();

// display tenant list

}; // end class tenantList

 

/////////////////////class tenantInputScreen//////////////////// class tenantInputScreen

{

private:

tenantList* ptrTenantList; string tName;

int aptNo;

public:

tenantInputScreen(tenantList* ptrTL) : ptrTenantList(ptrTL) { /* empty */ }

void getTenant();

}; //end class tenantInputScreen

//////////////////////////class rentRow///////////////////////// // one row of the rent record: an address and 12 rent amounts class rentRow

{

private: int aptNo;

float rent[12];

 

 

Object-Oriented Software Development

public:

 

 

 

 

rentRow(int);

// 1-arg ctor

void setRent(int, float);

// record rent for one month

float getSumOfRow();

// return sum of rents in row

// needed to store in ‘set’

 

friend

bool operator < (const rentRow&, const rentRow&);

friend

bool operator == (const rentRow&, const rentRow&);

// for

output

 

friend

ostream& operator << (ostream&, const rentRow&);

}; //

end class rentRow

 

////////////////////////////////////////////////////////////////

class compareRows //function object -- compares rentRows

{

public:

bool operator () (rentRow*, rentRow*) const;

};

/////////////////////////class rentRecord/////////////////////// class rentRecord

{

private:

// set of pointers to rentRow objects (one per tenant) set<rentRow*, compareRows> setPtrsRR;

set<rentRow*, compareRows>::iterator iter;

public:

~rentRecord();

void insertRent(int, int, float);

void display();

 

float getSumOfRents();

// sum all rents in record

}; // end class rentRecord

 

/////////////////////////class rentInputScreen////////////////// class rentInputScreen

{

private:

tenantList* ptrTenantList; rentRecord* ptrRentRecord;

string renterName; float rentPaid; int month;

int aptNo;

827

16

O D BJECT EVELOPMENT S

OFTWARE - RIENTEDO

Chapter 16

828

public:

rentInputScreen(tenantList* ptrTL, rentRecord* ptrRR) : ptrTenantList(ptrTL), ptrRentRecord(ptrRR)

{

/*empty*/ }

 

 

void

getRent();

//rent

for one tenant and one month

};

// end class rentInputScreen

 

////////////////////////////class expense/////////////////////// class expense

{

public:

int month, day;

string category, payee; float amount;

expense()

{}

expense(int m, int d, string c, string p, float a) : month(m), day(d), category(c), payee(p), amount(a)

{ /*empty */ }

//needed for use in ‘set’

friend

bool operator

< (const expense&, const expense&);

friend

bool operator

== (const expense&, const expense&);

// needed for output

 

friend

ostream& operator << (ostream&, const expense&);

}; //

end class expense

////////////////////////////////////////////////////////////////

class compareDates //function object--compares expenses

{

public:

bool operator () (expense*, expense*) const;

};

////////////////////////////////////////////////////////////////

class compareCategories //function object--compares expenses

{

public:

bool operator () (expense*, expense*) const;

};

////////////////////////class expenseRecord///////////////////// class expenseRecord

{

private:

// vector of pointers to expenses vector<expense*> vectPtrsExpenses; vector<expense*>::iterator iter;

 

Object-Oriented Software Development

public:

 

 

~expenseRecord();

 

void insertExp(expense*);

 

void display();

 

float displaySummary();

// used by annualReport

}; // end class expenseRecord

 

/////////////////////class expenseInputScreen/////////////////// class expenseInputScreen

{

private:

expenseRecord* ptrExpenseRecord;

public:

expenseInputScreen(expenseRecord*); void getExpense();

}; // end class expenseInputScreen

///////////////////////class annualReport/////////////////////// class annualReport

{

private: rentRecord* ptrRR;

expenseRecord* ptrER; float expenses, rents;

public:

annualReport(rentRecord*, expenseRecord*); void display();

}; // end class annualReport

///////////////////////class userInterface////////////////////// class userInterface

{

private:

tenantList* ptrTenantList; tenantInputScreen* ptrTenantInputScreen; rentRecord* ptrRentRecord; rentInputScreen* ptrRentInputScreen; expenseRecord* ptrExpenseRecord; expenseInputScreen* ptrExpenseInputScreen; annualReport* ptrAnnualReport;

char ch;

public:

userInterface();

829

16

O D BJECT EVELOPMENT S

OFTWARE - RIENTEDO

Chapter 16

830

~userInterface(); void interact();

}; // end class userInterfac

//////////////////////////end file landlord.h//////////////////////

Class Declarations

Declaring classes is the easy part. Most class declarations arise directly from the classes discovered by examining the nouns in the use case descriptions and seen on the class diagram. The names are changed from the multi-word English versions to single-word computerese, so that, for example, Tenant List becomes tenantList.

A few new classes have been added. We’ll find that we’re storing pointers to objects in various kinds of STL containers. This means that we must define comparison objects for these containers, as described in Chapter 15, “The Standard Template Library.” These comparison objects are actually classes named compareTenants, compareRows, compareDates, and compareCategories.

Attribute Declarations

As we noted, many of the attributes (member data) for each class can be determined from nouns that weren’t used for classes. For example, name and aptNumber become attributes of the tenant class declaration.

Other attributes can be inferred from the associations in the class diagram. Associations may indicate attributes that are pointers or references to other classes. This is because you can’t associate with something if you can’t find it. Thus the rentInputScreen class has the attributes ptrTenantList and ptrRentRecord.

Aggregates

Aggregate associations are shown in three places on the class diagram. Often, aggregates indicate containers that are attributes of the containing class (the whole) holding objects (the parts).

Neither the use case descriptions nor the class diagram suggest what sort of container should be used for these aggregates. As a programmer, you’ll need to choose an appropriate container for each aggregate, whether it’s a simple array, an STL container, or something else. In LANDLORD, we made the following choices:

The tenantList class contains an STL set of pointers to tenant objects.

The rentRecord class contains a set of pointers to rentRow objects.

The expenseRecord class contains a vector of pointers to expense objects.

Object-Oriented Software Development

We used sets for tenantList and rentRecord to provide fast access. We used a vector for expenseRecord because we need to sort the Expense objects both by date and by category, and vectors (unlike sets) can be sorted efficiently.

In all the aggregations, we chose to store pointers, rather than actual objects, to avoid the copying that takes place every time an actual object is stored. Storing objects directly might be appropriate in situations where the objects are small and there aren’t many of them. Of course, the performance penalty for storing objects isn’t great in a small program like this, but for efficiency you should always consider storing pointers.

The .CPP Files

The .CPP files contain the method bodies whose declarations were given in the .H file. Writing the code for these methods should be fairly straightforward at this point. You know the function name, what it’s supposed to do, and probably the arguments passed to it.

We’ve separated the class method definitions from main(), which is in the short LORDAPP.CPP file. In main() a userInterface object is created and its interact() method is called. Here’s the LORDAPP.CPP file:

//lordApp.cpp

//client file for apart program #include “landlord.h”

int main()

{

userInterface theUserInterface;

theUserInterface.interact(); return 0;

}

////////////////////////end file lordApp.cpp////////////////////

Finally, here’s the LANDLORD.CPP file, which contains all the class method definitions.

//landlord.cpp

//models the finances for an apartment building #include “landlord.h” //for class declarations, etc.

//////////////////////global functions//////////////////////// void getaLine(string& inStr) // get line of text

{

char temp[21]; cin.get(temp, 20, ‘\n’); cin.ignore(20, ‘\n’); inStr = temp;

}

831

16

O D BJECT EVELOPMENT S

OFTWARE - RIENTEDO

832

Chapter 16

 

//--------------------------------------------------------------

 

char getaChar()

// get a character

{

 

char ch = cin.get();

 

cin.ignore(80, ‘\n’);

 

return ch;

 

}

 

//--------------------------------------------------------------

 

/////////////////////methods for class tenant/////////////////// tenant::tenant(string n, int aNo) : name(n), aptNumber(aNo)

{ /* empty */ } //--------------------------------------------------------------

tenant::~tenant() { /* empty */ }

//--------------------------------------------------------------

int tenant::getAptNumber() { return aptNumber; }

//--------------------------------------------------------------

bool operator < (const tenant& t1, const tenant& t2) { return t1.name < t2.name; }

//--------------------------------------------------------------

bool operator == (const tenant& t1, const tenant& t2) { return t1.name == t2.name; }

//--------------------------------------------------------------

ostream& operator << (ostream& s, const tenant& t)

{ s << t.aptNumber << ‘\t’ << t.name << endl; return s; } //--------------------------------------------------------------

////////////////method for class tenantInputScreen//////////////

void tenantInputScreen::getTenant()

//get tenant info

{

 

 

cout << “Enter

tenant’s name (George Smith): “;

getaLine(tName);

 

cout << “Enter

tenant’s apartment number (101): “;

cin >> aptNo;

 

 

cin.ignore(80,

‘\n’);

//make tenant

tenant* ptrTenant = new tenant(tName, aptNo); ptrTenantList->insertTenant(ptrTenant); //send to tenant list

}

////////////////////////////////////////////////////////////////

bool compareTenants::operator () (tenant* ptrT1, tenant* ptrT2) const

{ return *ptrT1 < *ptrT2; } //--------------------------------------------------------------

Object-Oriented Software Development

///////////////////methods for class tenantList/////////////////

tenantList::~tenantList()

//destructor

{

 

 

while( !setPtrsTens.empty() )

//delete all tenants,

 

{

//remove ptrs from set

 

iter = setPtrsTens.begin();

 

 

delete *iter;

 

 

setPtrsTens.erase(iter);

 

 

}

 

}

// end ~tenantList()

 

//--------------------------------------------------------------

 

 

void tenantList::insertTenant(tenant* ptrT)

{

 

 

setPtrsTens.insert(ptrT);

//insert

}

 

 

//--------------------------------------------------------------

 

 

int tenantList::getAptNo(string tName) //name on list?

{

 

 

int aptNo;

 

tenant dummy(tName, 0);

 

iter = setPtrsTens.begin();

 

while( iter != setPtrsTens.end() )

 

 

{

 

 

aptNo = (*iter)->getAptNumber(); //look for tenant

 

if(dummy == **iter++)

//on the list?

 

return aptNo;

//yes

 

}

 

return -1;

//no

}

 

 

//--------------------------------------------------------------

 

 

void tenantList::display()

//display tenant list

{

 

 

cout << “\nApt#\tTenant name\n-------------------

\n”;

if( setPtrsTens.empty() )

 

 

cout << “***No tenants***\n”;

 

else

 

 

{

 

 

iter = setPtrsTens.begin();

 

 

while( iter != setPtrsTens.end() )

 

cout << **iter++;

 

 

}

 

}

// end display()

 

//--------------------------------------------------------------

 

 

/////////////////////methods for class rentRow////////////////// rentRow::rentRow(int an) : aptNo(an) // 1-arg constructor

{ fill( &rent[0], &rent[12], 0); }

833

16

O D BJECT EVELOPMENT S

OFTWARE - RIENTEDO

834

Chapter 16

 

//--------------------------------------------------------------

void rentRow::setRent(int m, float am)

{

rent[m] = am; }

 

 

//--------------------------------------------------------------

 

 

 

float rentRow::getSumOfRow()

// sum of rents in row

{

return accumulate( &rent[0], &rent[12], 0); }

//--------------------------------------------------------------

 

 

 

bool operator < (const rentRow& t1, const rentRow& t2)

{ return t1.aptNo < t2.aptNo; }

//--------------------------------------------------------------

 

 

 

bool operator == (const rentRow& t1, const rentRow& t2)

{ return t1.aptNo == t2.aptNo; }

//--------------------------------------------------------------

 

 

 

ostream& operator << (ostream& s, const rentRow& an)

{

 

 

 

s << an.aptNo << ‘\t’;

//print apartment number

for(int j=0; j<12; j++)

//print 12 rents

 

{

 

 

 

if(an.rent[j]

== 0)

 

 

s << “ 0

“;

 

 

else

 

 

 

s << an.rent[j] << “

“;

}

s << endl; return s;

}

////////////////////////////////////////////////////////////////

bool compareRows::operator () (rentRow* ptrR1, rentRow* ptrR2) const

{ return *ptrR1 < *ptrR2; }

///////////////////methods for class rentRecord/////////////////

rentRecord::~rentRecord()

//destructor

{

 

while( !setPtrsRR.empty() )

//delete rent rows,

{

//remove ptrs from set

iter = setPtrsRR.begin();

 

delete *iter;

 

setPtrsRR.erase(iter);

 

}

 

}

 

//--------------------------------------------------------------

 

void rentRecord::insertRent(int aptNo, int month, float amount)

{

 

rentRow searchRow(aptNo);

//temp row with same aptNo

iter = setPtrsRR.begin();

//search setPtrsRR