Question: This assignment has all of the functionality of project 2, but will be rewritten to use a class, and will have the addition of a

This assignment has all of the functionality of project 2, but will be rewritten to use a class, and will have the addition of a writeData() function. You will also be required to have at least two source code files and a header file for this project. See below for more details. This project will load data from a text file into memory, and have a menu driven loop to search the data for a workout type, add new data, list all data, and quit. Move the code for adding new data into a separate member function, perhaps called add(). In addition, at program termination when the user chooses to quit, you will write the new data back to the same text file. So, if you read the data from an input file called exercises.txt, you will write the new data back to the same file, exercises.txt. Make sure that your program only reads from the file when the program starts, and writes to the file at program termination. For example, dont open the file, search it, and close it again in the search() function. You may only search, list, or add the data in and to memory (the array that is part of the class). You have two options for this: you can open the file for reading and appending, or you can read the data, close the file, reopen the same file for output, and rewrite all of the data (both the data read from the file and the new data entered by the user).

struct exerciseData {

char name[strSize];

char date[strSize];

char note[strSize];

int time;

int calories;

int maxHeartRate;

};

One of the programming concepts that classes allow us to implement is called encapsulation. To implement encapsulation, you will move all of the functions that were part of project 2 into the class. To get used to the idea of encapsulation, you may not pass any arguments to your member functions. So, there will be no formal parameters in your prototypes. Remember that you may not use global variables either, so all of the items that your member functions need will be encapsulated in the class.

class exerciseJournal {

exerciseData [arraySize];

int countAndIndex;

char fileName[strSize];

public:

int loadData();

void writeData();

void add();

bool search();

void listAll();

};

Program Requirements

For assignment 2, we declared an array of exerciseData structs inside of the main function. We will still need an array of exerciseData structs for this assignment, but instead of declaring the array in the main function, the array will be moved inside of the class, along with all of the relevant functions that you defined for assignment 2. Put another way, the functions and data items (the array) will be encapsulated inside of the class. So, all of the functions you write for this assignment will be public member functions, and all of the data items will be private members (or properties) of the class. Do not create an array of exerciseData structs inside of main().

You must separate your code for this assignment into at least two separate code files and a header file. Place the main function in one source code file, and the class implementation in another source code file. The implementation file for a class contains the member function definitions. The struct and class definitions must be placed into a header file, along with included libraries, and globally declared constants. Prototypes for nonmember functions should go in the header file as well, but this project will not use any.

Take a look at the class definition for exerciseJournal above. Notice that all of the stand-alone functions that were part of assignment 2 are now member functions. Also notice that the exerciseData array, countAndIndex value, and fileName c-string are declared above the public label. This means that they are private members, and cannot be accessed by functions that are not member functions (or friend functions). So for example, the exerciseData array cannot be directly accessed from main(). This is called data hiding.

Also notice that add() has been added to the class as a member function. You may have created an add() function for project 2 or you may have placed the code inside of the main function. In this project, the code for adding new data has to be inside of its own member function, add().

Make sure you check for index out of bounds before adding new data to the array, both inside of the loadData() function and in the add() function. When loading or adding data, compare the countAndIndex value to the arraySize constant. If they are equal, there is no more room in the array.

Check to make sure that the input file is open before reading from it, using ifstream.is_open(). You may terminate the program if the file does not open, or you may ask the user to try a different file name.

You may assume that the data from the file is correctly formatted. In contrast, do not assume that the user will input proper data, so check for bad data when reading from cin (just like with project 2).

Dont use string objects or any STL containers such as vectors. Use c-strings and the library for string manipulation (strcmp(), strcpy(), etc.). You may use a reasonable length for your c-strings and arrays, such as 256 or 128, declared as global constants (remember not to use literals in your code):

const int strSize = 256; const int arraySize = 128;

Programming Strategies

After you create your class and struct definitions in the header file, create a separate file called exerciseImplemenation.cpp or implementation.cpp, or some other descriptive name. Place all of the member functions in this file. Then create another source code file called exerciseMain.cpp, or just main.cpp. Place the main function in this file. You will have to include your header file in both of the source code files in order to get the project to compile correctly. Suppose the name of your header file is exerciseHeader.hpp (or you can use the extension .h). Then to include the header file in both source code files, use:

#include exerciseHeader.hpp // (or exerciseHeader.h)

at the top of both source code files. Notice the double quotes there instead of angled brackets (<>). The double quotes direct g++ to look inside of the current directory to find the header file. Remember that because the header file is included in the source code files, it is not necessary to list the header file on the command line during compilation. So, to compile your project, it may look like this:

g++ main.cpp implementation.cpp o exerciseProgram

Remember that headers for member functions have to include the name of the class and the scope resolution operator. So the loadData() method header might look like:

int exerciseJournal::loadData()

int main()

{

exerciseJournal myExercises;

int count;

count = myExercises.loadData();

cout << Exercises loaded: << count;

// the rest of the code here.

// user controlled loop, etc.

// ready for program termination.

myExercises.writeData();

return 0;

}

Once you have created your exerciseJournal class and implementation, you will have to instantiate it, or create an exerciseJournal object, in the main function. Then you will use the object to call the member functions. See the textbox to the right and above for an example.

Notice that I have placed the fileName c-string inside of the class, along with the countAndIndex member variable. I did this so that the file name will be accessible to all of the member functions that need it, such as loadData() and writeData(). Since the file name is part of the class, it wont have to be passed as an argument. You may add any other member variables to the class that you feel you need, such as the fstream object, other c-strings, counting variables, or whatever, but make sure you add them as private members. You may also create other member functions if you find that you need them. For example, if you wish to have access to the countAndIndex value in main, you will need a getter (accessor) function for it. So the prototype (inside of the class) would be: int getCountAndIndex(); and the header would be:

int exerciseJournal::getCountAndIndex()

Remember that any member functions that you want the client (main function in this case) to use must be declared as public, so if you create any, put the getter functions after the public label.

As mentioned above, you have two options for reading and writing to the same file. The first (simpler) option is to open the file in loadData using an ifstream, read all the data into memory, and then close the file. At program termination, open the file using an ofstream, write all of the data in memory back to the file, and then close the file. Remember that when you open a file for output, if the file already exists, all of the data in the file is deleted. Your second option is to make the file object a member of the class, and then open the file for reading and appending. That way, you can open the file in loadData(), read all of the data, and then leave the file open. Then at program termination, just write the new data to the file. So if the user enters new exercise data, only that new data should be written to the file. If the user doesnt enter new data, then nothing new gets written to the file. Remember to close all files either way. To open a file for reading and appending, create a file object and open it with the ios::in and ios::app options:

fstream file;

// ask the user for the fileName.

file.open(fileName, ios::in | ios::app); // one pipe (|) for bitwise or.

-----------------------------------------------

Here is Project2 file below.

------------------------------------------------

//CS162 Project2

#include

#include

#include

using namespace std;

// Reusable stuff -------------------------------

const int STRING_SIZE = 64;

const int LIST_SIZE = 4096;

// Return true if any char in cs satisfies condition.

// condition has type 'int (*condition)(int)' to match

convention.

bool any(const char cs[], int (*condition)(int)) {

for (int i = 0; cs[i]; i++)

if (condition(cs[i]))

return true;

return false;

}

// The q prefix indicates a function that queries the user.

// Ask the user a question. Dump the response into answer.

void qCString(const char question[], char answer[],

const int ss = STRING_SIZE) {

cout << question << ' ';

cin.getline(answer, ss);

}

// Bother the user until they enter a string containing graphical

characters.

void qGCString(const char question[], char answer[],

const int ss = STRING_SIZE) {

qCString(question, answer, ss);

while (!any(answer, isgraph))

qCString("Try again:", answer, ss);

}

// Bother the user until they enter a valid integer. Return the integer.

int qInt(const char question[]) {

int resp;

bool fail;

cout << question << ' ';

while (true) {

cin >> resp;

fail = cin.fail();

cin.clear();

cin.ignore(STRING_SIZE, ' ');

if (!fail)

break;

cout << "Try again: ";

}

return resp;

}

// Bother the user until they enter a positive integer. Return the

integer.

int qPInt(const char question[]) {

int response = qInt(question);

while (response <= 0)

response = qInt("Try again:");

return response;

}

// Get a character from user. Consumes entire line.

char qChar(const char question[]) {

cout << question << ' ';

const char resp = cin.peek();

cin.ignore(STRING_SIZE, ' ');

return resp;

}

// Return whether cs contains c.

bool contains(const char cs[], const char c) {

for (int i = 0; cs[i]; i++)

if (cs[i] == c)

return true;

return false;

}

// Bother user until they enter an allowed character.

char qSelection(const char question[], const char allowed[]) {

char resp = qChar(question);

while (!contains(allowed, resp))

resp = qChar("Try again:");

return resp;

}

// Bother the user until they enter y or n. Return true for y, false for

n.

bool qYN(const char question[]) { return qSelection(question, "yn") ==

'y'; }

// Bother the user for a path to a real file. Return the open file.

void qFH(const char question[], ifstream& fh) {

char filename[STRING_SIZE];

qCString(question, filename);

fh.open(filename);

while (!fh.is_open()) {

qCString("Try again:", filename);

fh.open(filename);

}

}

// End of reusable stuff ------------------------

struct exerciseData {

char name[STRING_SIZE];

char date[STRING_SIZE];

char note[STRING_SIZE];

int time;

int calories;

int maxHeartRate;

};

// Populate an activity from user input.

void queryActivty(exerciseData &ed) {

qGCString("What exercise activity did you do?", ed.name);

qGCString("What was the date (mm/dd/yy):", ed.date);

ed.time = qPInt("How many minutes?");

ed.calories = qPInt("How many calories did you burn?");

ed.maxHeartRate = qPInt("What was you max heart rate?");

qGCString("Do you have any notes to add?", ed.note);

}

// Populate an activity from a line in a csv.

bool parseActivity(exerciseData &ed, ifstream &fh) {

fh.getline(ed.name, STRING_SIZE, ',');

fh.getline(ed.date, STRING_SIZE, ',');

fh.getline(ed.note, STRING_SIZE, ',');

fh >> ed.time;

fh.ignore();

fh >> ed.calories;

fh.ignore();

fh >> ed.maxHeartRate;

fh.ignore();

}

// Load all the data from a csv. Return number of loaded elements.

int loadData(exerciseData eds[LIST_SIZE]) {

int size = 0;

ifstream fh;

qFH("What is the name of the exercise data text file to load?", fh);

while (fh && size < LIST_SIZE){

parseActivity(eds[size++], fh);

cout << "(bool)fh : " << (bool)fh << ' ';

cout << "size: " << size << ' ';

}

return size;

}

// Search for specific exercise name. Print all matches.

void search(exerciseData eds[], int count) {

char name[STRING_SIZE];

qGCString("What activity would you like to search for?", name);

cout << "Here are the activities matching" << name << ": ";

cout << "Name Date Time Calories Max Heartrate

Note ";

for (int i = 0; i < count; i++)

if (strcmp(name, eds[i].name) == 0)

cout << eds[i].name << ' ' << eds[i].date << ' ' << eds[i].time <<

' '

<< eds[i].calories << ' ' << eds[i].maxHeartRate << ' '

<< eds[i].note << ' ';

}

// Pretty print all the exercises.

void list(exerciseData eds[], int count) {

cout << "Name Date Time Calories Max Heartrate

Note ";

for (int i = 0; i < count; i++)

cout << eds[i].name << ' ' << eds[i].date << ' ' << eds[i].time << '

'

<< eds[i].calories << ' ' << eds[i].maxHeartRate << ' ' <<

eds[i].note

<< ' ';

}

// Ask user to enter an exercise. Increments count if user chooses to

save.

void add(exerciseData eds[], int &count) {

if (count >= LIST_SIZE) {

cout << "You need to stop exercising. ";

} else {

queryActivty(eds[count]);

if (qYN("Record the activity time and calories (y/n)?")) {

count++;

cout << "Your activity info has been recorded. ";

}

}

}

int main() {

exerciseData eds[LIST_SIZE];

int size;

cout << "Welcome to the exercise tracking program. ";

size = loadData(eds);

while (true) {

const char s = qSelection("What would you like to do: (l)ist all,

(s)earch "

"by name, (a)dd an exercise, or (q)uit?

:",

"lsaq");

if (s == 'l') {

list(eds, size);

} else if (s == 's') {

search(eds, size);

} else if (s == 'a') {

add(eds, size);

} else if (s == 'q') {

break;

}

};

cout << "Thank you for using the exercise tracking program. ";

return 0;

}

Step by Step Solution

There are 3 Steps involved in it

1 Expert Approved Answer
Step: 1 Unlock blur-text-image
Question Has Been Solved by an Expert!

Get step-by-step solutions from verified subject matter experts

Step: 2 Unlock
Step: 3 Unlock

Students Have Also Explored These Related Databases Questions!