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

lafore_robert_objectoriented_programming_in_c

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

Multifile Programs

655

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

verylong verylong::operator * (const verylong v) //multiply

{

 

//verylongs

verylong pprod;

//product of one digit

verylong tempsum;

//running total

for(int j=0; j<v.vlen; j++)

//for each digit in arg

{

 

 

int digit = v.vlstr[j]-’0’;

//get the digit

pprod = multdigit(digit);

//multiply this by digit

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

//multiply result by

pprod = mult10(pprod);

//

power of 10

tempsum = tempsum + pprod;

//add product to total

}

 

 

return tempsum;

//return total of prods

}

 

 

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

 

 

verylong verylong::mult10(const verylong v) const //multiply

{

 

//arg by 10

char temp[SZ];

 

 

for(int j=v.vlen-1; j>=0; j--)

//move digits one

temp[j+1] = v.vlstr[j];

//

position higher

temp[0] = ‘0’;

//put zero on low end

temp[v.vlen+1] = ‘\0’;

//terminate string

return verylong(temp);

//return result

}

 

 

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

 

 

verylong verylong::multdigit(const int d2) const

{

//multiply this verylong

char temp[SZ];

//by digit in argument

int j, carry = 0;

 

 

for(j = 0; j<vlen; j++)

//for each position

{

//

in this verylong

int d1 = vlstr[j]-’0’;

//get digit from this

int digitprod = d1 * d2;

//multiply by that digit

digitprod += carry;

//add old carry

if( digitprod >= 10 )

//if there’s a new carry,

{

 

 

carry = digitprod/10;

//carry is high digit

digitprod -= carry*10;

//result is low digit

}

 

 

else

 

 

carry = 0;

//otherwise carry is 0

temp[j] = digitprod+’0’;

//insert char in string

}

 

 

if(carry != 0)

//if carry at end,

temp[j++] = carry+’0’;

//it’s last digit

13

PROGRAMS MULTIFILE

656

Chapter 13

 

temp[j] = ‘\0’;

//terminate string

return verylong(temp);

//return verylong

}

 

The putvl() and getvl() functions are fairly straightforward. They use the strrev() C library function to reverse the C-string, so it is stored in reverse order but input is displayed normally.

The operator+() function adds two verylongs and leaves the result in a third verylong. It does this by considering their digits one at a time. It adds digit 0 from both numbers, storing a carry if necessary. Then it adds the digits in position 1, adding the carry if necessary. It continues until it has added all the digits in the larger of the two numbers. If the numbers are different lengths, the nonexistent digits in the shorter number are set to 0 before being added. Figure 13.3 shows the process.

FIGURE 13.3

Adding verylong numbers.

Multifile Programs

657

Multiplication uses the operator*() function. This function multiplies the multiplicand (the top number when you write it by hand) by each separate digit in the multiplier (the bottom number). It calls the multdigit() routine to this. The results are then multiplied by 10 an appropriate number of times to shift the result to match the position of the digit, using the mult10() function. The results of these separate calculations are then added together using the operator+() function.

The Application Program

To test the verylong class we use a variation of the FACTOR program from Chapter 3, “Loops and Decisions,” to calculate the factorial of a number entered by the user. Here’s the listing for

VL_APP.CPP:

//vl_app.cpp

//calculates factorials of larger numbers using verylong class

#include “verylong.h”

//verylong header file

int main()

 

 

{

 

 

unsigned long numb, j;

 

 

verylong fact=1;

//initialize verylong

cout << “\n\nEnter number: “;

 

 

cin >> numb;

//input a long int

for(j=numb; j>0; j--)

//factorial is numb *

fact = fact * j;

//

numb-1 * numb-2 *

cout << “Factorial is “;

//

numb-3 and so on

fact.putvl();

//display factorial

cout << endl;

 

 

return 0;

 

 

}

 

 

In this program fact is a verylong variable. The other variables, numb and j, don’t need to be verylongs because they don’t get so big. To calculate the factorial of 100, for example, numb and j require only three digits, while fact requires 158.

Notice how, in the expression

fact = fact * j;

the long variable j is automatically converted to verylong, using the one-argument constructor, before the multiplication is carried out.

13

PROGRAMS MULTIFILE

Chapter 13

658

Here’s the output when we ask the program to find the factorial of 100:

Enter number: 100

Factorial is 9332621544394415268169923885626670049071596826438162 1468592963895217599993229915608941463976156518286253697920827223 758251185210916864000000000000000000000000

Try that using type long variables! Surprisingly, the routines are fairly fast; this program executes in a fraction of a second. You can calculate the factorial of numbers up to about 400 before you exceed the 1000 digit capacity of the program.

A High-Rise Elevator Simulation

The next time you’re waiting for an elevator in a high-rise office building, ask yourself how the elevators figure out where to go. In the old days, of course, there was a human elevator operator on each car. (“Good morning, Mr. Burberry,” “Good morning, Carl.”) Riders needed to tell the operator their destination floor when getting on (“Seventeen, please.”). A panel of signal lights lit up inside the car to show which floors were requesting service up or down. Operators decided which way to go and where to stop on the basis of these verbal requests and their observation of the signal lights.

Nowadays enough intelligence is built into elevator systems to permit the cars to operate on their own. In our next example we use C++ classes to model an elevator system.

What are the components of such a system? In a typical building there are a number of similar elevators. On each floor there are up and down buttons. Note that there is usually only one such pair of buttons per floor; when you push a button you don’t know which elevator will stop for you. Within the elevator there is a larger number of buttons: one for each floor. After entering the elevator, riders push a button to indicate their destination. Our simulation program will model all these components.

Running the ELEV Program

When you start up the ELEV program you’ll see four elevators sitting at the bottom of the screen, and a list of numbers on the left, starting at 1 on the bottom of the screen and continuing up to 20 at the top. The elevators are initially on the ground (first) floor. This is shown in Figure 13.4.

Multifile Programs

659

FIGURE 13.4

The ELEV program initial screen.

Making a Floor Request

If you press Enter, text at the bottom of the screen prompts

Enter the floor you’re on:

You can enter any floor number from 1 to 20. If you’ve just arrived for work on the ground floor, you’ll enter 1. If you’re leaving a higher floor to go out to lunch, you’ll enter your floor’s number. The next prompt is

Enter direction you want to go (u or d):

If you’re on the first floor you must go up, and if you’re on the 20th floor you must go down. For intermediate floors you can go either way. When you’ve completed your floor request, a triangle will appear next to the appropriate floor number on the left. It will point either up or down, depending on the direction you requested. As more requests are made, triangles will appear beside additional floor numbers.

If there is an elevator car already at a floor where a request has been made, the door will open immediately. You’ll see a happy-face character materialize outside the car, then move into the open door. If there is no car on the floor making the request, one will move up or down toward the floor and open its door once it reaches the floor.

13

PROGRAMS MULTIFILE

Chapter 13

660

Entering Destinations

Once a car arrives at a floor and the happy-face passenger is inside, a prompt appears on the bottom of the screen:

Car 1 has stopped at floor 1

Enter destination floors (0 when finished)

Destination 1: 13

Here the passenger has entered 13. However, the happy face can represent more than one passenger getting on at once. Each passenger may request a different destination, so the program allows multiple destinations to be entered. Enter as many numbers as you want (at least 1, but no more than 20) and enter 0 when you’re done.

The destinations requested by passengers within a particular car are indicated by small rectangles displayed outside the car, just to its left, opposite the floor number requested. Each car has its own set of destinations (unlike floor requests, which are shared by all the cars).

You can make as many floor requests as you like. The system will remember the requests, along with the destinations selected from within each car, and attempt to service them all. All four cars may be in motion at the same time. Figure 13.5 shows a situation with multiple floor requests and multiple destinations.

FIGURE 13.5

Elevators in action.

Designing the System

The elevator cars are all roughly the same, so it seems reasonable to make them objects of a single class, called elevator. This class will contain data specific to each car: its present location, the direction it’s going, the destination floor numbers requested by its occupants, and so on.

Multifile Programs

661

However, there is also data that applies to the building as a whole. This data will be part of the building class. First there is an array of floor requests. This is a list of floors where people, waiting for the elevator, have pushed the up or down button to request that an elevator stop at their floor. Any elevator may respond to such a floor request, so each one needs to know about them. We use an N-by-2 array of type bool, where N is the number of floors and the 2 allows separate array elements for up and down for each floor. All the elevators can look at this array when they’re trying to figure out where to go next.

Besides knowing about the floor requests, each elevator car must also be aware of where the other elevators are. If we’re on the first floor, there’s no point in rushing up to the 15th floor to answer a request if there’s already another car available on the 10th floor. The closest car should head toward the request. To make it easy for each car to find out about the others, the second data item in building is an array of pointers to elevators. Each elevator car stores its memory address on this list when it’s first created, so the other cars can find it.

The third data item in the building class is the number of cars created so far. This allows each car to number itself sequentially when it’s created.

Managing Time

The main() program calls a member function of building at fixed intervals to put things into motion. This function is called master_tick(). It in turn calls a function for each elevator car, called car_tick1(). This function, among other things, displays each car on the screen and calls another function to decide what the car should do next. The choices are to go up, to go down, to stop, to load a passenger, or to unload a passenger.

Each car must then be moved to its new position. However, things get slightly complicated here. Because each car must figure out where the other ones are before it can decide what to do, all the cars must go through the decision process before any of them moves. To make sure this happens, we use two time ticks for each car. Thus after car_tick1() has been called to decide where each car will go, another function, car_tick2(), is called to actually move each car. It causes the cars to move by changing the variable current_floor.

The process of loading passengers follows a fixed sequence of steps, during which the car is stopped at the desired floor. The program draws, in order

1.Car with closed door, no happy face.

2.Car with open door, happy face on left.

3.Car with happy face in open door, get destinations from user.

4.Car with closed door, no happy face.

13

PROGRAMS MULTIFILE

Chapter 13

662

The reverse sequence applies to unloading. These sequences are carried out by starting a timer (an integer variable) and letting it count down from 3 to 0, decrementing it with each time tick. A case statement in the car_display() function then draws the appropriate version of the car for each stage of the process.

Because the ELEV program uses various console graphics functions, it requires a header file available from this book’s publisher; either MSOFTCON.H for Microsoft compilers or BORLACON.H for Borland compilers. (See Appendix E, “Console Graphics Lite.”)

Listings for ELEV

We’ve divided the program into four files. Two of these files, ELEV.H and ELEV.CPP, might be created by a vendor supplying elevator-control software. This software would then be purchased by an engineering company interested in designing an elevator system for a particular building. (This program is not certified by the National Elevator Board, so don’t try it with real elevators.) The engineering company would then write another pair of files, ELEV_APP.H and ELEV_APP.CPP. The ELEV_APP.H file specifies the characteristics of the high-rise building. It needs to be a separate file because these characteristics must be known by the elevator class member functions, and the easiest way to do this is to include ELEV_APP.H in the ELEV.H file. The ELEV_APP.CPP file initializes the elevators and then calls elevator functions at fixed intervals to simulate the passage of time.

Class Specifier

The ELEV.H file contains the specification for the elevator class. The array of pointers to elevators, car_list[], allows each elevator to query all the others about their location and direction. Here’s the listing:

//elev.h

//header file for elevators -- contains class declarations

#include “elev_app.h”

//provided by client

#include “msoftcon.h”

//for console graphics

#include <iostream>

 

#include <iomanip>

//for setw()

#include <conio.h>

//for screen output

#include <stdlib.h>

//for itoa()

#include <process.h>

//for exit()

using namespace std;

 

 

 

enum direction { UP, DN, STOP

};

 

const int LOAD_TIME =

3;

//loading/unloading time

(ticks)

const

int

SPACING =

7;

//visual spacing between

cars

const

int

BUF_LENGTH =

80;

//length of utility string buffer

Multifile Programs

663

class building; //forward declaration

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

class elevator

 

 

{

 

 

private:

 

 

building* ptrBuilding;

//ptr to parent building

const int car_number;

//our number (0 to nc-1)

int current_floor;

//where are we? (0 to nf-1)

int old_floor;

//where were we? (0 to nf-1)

direction current_dir;

//which way are we going?

bool destination[NUM_FLOORS];

//selected by

occupants

int loading_timer;

//non-zero if

loading

int unloading_timer;

//non-zero if

unloading

public:

 

 

elevator(building*, int);

//constructor

 

void car_tick1();

//time tick 1

for each car

void car_tick2();

//time tick 2

for each car

void car_display();

//display elevator

void dests_display() const;

//display elevator requests

void decide();

//decide what

to do

void move();

//move the car

 

void get_destinations();

//get destinations

int get_floor() const;

//get current

floor

direction get_direction() const; //get current direction };

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

class building

 

{

 

private:

 

elevator* car_list[NUM_CARS];

//ptrs to cars

int num_cars;

//cars created so far

 

//array of up/down buttons

bool floor_request[2][NUM_FLOORS]; //false=UP, true=DN

public:

 

building();

//constructor

~building();

//destructor

void master_tick();

//send ticks to all cars

int get_cars_floor(const int) const; //find where a car is //find which way car is going

direction get_cars_dir(const int) const;

//check specific floor req bool get_floor_req(const int, const int) const;

//set specific floor req

13

PROGRAMS MULTIFILE

Chapter 13

664

void set_floor_req(const int, const int, const bool); void record_floor_reqs(); //get floor requests void show_floor_reqs() const; //show floor requests };

Member Functions

The ELEV.CPP file contains the definitions of the elevator class and building class member functions and data. Functions in building initialize the system, provide a master time tick, display the floor requests, and get floor requests from the user. Functions in elevator initialize individual cars (with the constructor), provide two time ticks for each car, display it, display its destinations, decide what to do, move the car to a new floor, and get destinations from the user. Here’s the listing:

//elev.cpp

//contains class data and member function definitions

#include “elev.h” //include class declarations

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

// function definitions for class building

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

building::building()

//constructor

{

 

char ustring[BUF_LENGTH];

//string for floor numbers

init_graphics();

//initialize graphics

clear_screen();

//clear screen

num_cars = 0;

 

for(int k=0; k<NUM_CARS; k++)

//make elevators

{

 

car_list[k] = new elevator(this, num_cars);

num_cars++;

 

}

 

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

//for each floor

{

set_cursor_pos(3, NUM_FLOORS-j); //put floor number

itoa(j+1, ustring, 10);

//on screen

cout << setw(3) << ustring;

 

floor_request[UP][j] = false;

//no floor requests yet

floor_request[DN][j] = false;

 

}

 

} //end constructor

 

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

 

building::~building()

//destructor

{

 

for(int k=0 k<NUM_CARS; k++)

 

delete car_list[k];

 

}