Question
Using a Class, multiple source files, and File Write write a C++ program on the PCC Linux system that keeps track of your most valuable
Using a Class, multiple source files, and File Write
write a C++ program on the PCC Linux system that keeps track of your most valuable Magic Cards. When the program starts, your program will ask the user to enter the name of an input file, which your program will open and use to load the card collection . After the file is loaded, the program will enter a user--controlled loop. Inside of the loop, the program will ask the user what they want to do. In addition to searching and listing, the user will have the option to add another card to the collection, So, the options that the user can select are:
Search for a card by name.
List all of the cards.
Add a new card
Quit.
To start you need 3 files for this project: one for the main function, one for the header file, and one for the implementation. Also, if the user enters a new card into the database in memory, you will need to write it to the card data file when the program terminates. So, the input file will also be used as an output file: read from it at the beginning of the program and write to it at program termination. See programming strategies below for how to read and write to the same file. Create an additional member function called writeCards(), as described in the class definition below. 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 now part of the class). See below for more details about the CardCollection class.
Search, list, add, and now write will be implemented using functions, but with a class, they will be member functions. See below for an example of the class definition and the encapsulation explanation
struct cardInfo {
char name[STR_SIZE];
double price;
char set[STR_SIZE];
char type[STR_SIZE];
int count;
};
the file format lists all of the information for one card on one line, and includes the name, price, set, type, and count.
All In Good Time,13.22,Archenemy,Scheme,1
Enlightened Tutor,14.25,Eternal Masters,Instant,3
Helm of Obedience,17.39,Alliances,Artifact,2
Liliana the Last Hope,25.55,Eldritch Moon,Planeswalker,1
Chaos Orb,7300.00,Beta,Artifact,1
Ugin the Spirit Dragon,32.80,Fate Reforged,Planeswalker,2
Temporal Trespass,1.77,Fate Reforged,Sorcery,4
Zodiac Dragon,239.99,Portal Three Kingdoms,Creature,1
One of the programming concepts that classes allow us to implement is called encapsulation
If you take a look at the class definition below, you will notice that the prototypes for the functions are now placed inside of it, in the public section.
class CardCollection {
cardInfo [arraySize];
int countAndIndex;
char fileName[strSize];
public:
CardCollection();
int loadCards();
void writeCards();
void addACard();
bool searchCards();
void listCards();
};
So the functions are now encapsulated and are called member functions. All member functions of a class have direct access to the other members of the class without scope resolution or the member access operator (the dot). To get used to the idea of encapsulation and manipulating member variables, you may not pass any arguments to your member functions. So, there will be no formal parameters in your prototypes and headings . 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 as member variables (properties). The cardInfo array is now a member and is no longer declared in main. Do not create an array of cardInfo structs anywhere else, such as in the main function. You must use the member array to store the card information. Notice that the cardInfo 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 non-member functions, only by member functions (or friend functions). So for example, the cardInfo array cannot be directly accessed from main(). This is called data hiding. In addition to the 5 member functions listed, there is one additional function called the default constructor. The default constructor is a special function, in that it is not called and it does not have a return type. The constructor is invoked automatically when the class is instantiated (an object variable is declared). The constructor for this project is very simple: all that needs to be done at this point is to initialize countAndIndex to zero.Lets take a look at how we might create the function headings, using searchCards() as an example. Remember that in the implementation source file, we need the name of the class and the scope resolution operator in front of the function name. Then, inside of the function definition, you may access countAndIndex, the cardInfo array, etc., directly:
bool CardCollection::searchCards() { // Remember, no formal parameters.
// Place any necessary local variables here, such as a loop counter.
for(i = 0; i < countAndIndex, ...) { // direct access to countAndIndex ...
if(strcmp(cardInfo[i].name, ... // and to the cardInfo array.
}
The function heading for the default constructor is very similar, but without a return type:
CardCollection::CardCollection() {
// Initialize countAndIndex to zero.
}
Programming Strategies
After you create or move your class and struct definitions in to the header file, create a separate file called cardCollectionImp.cpp or implementation.cpp, or some other descriptive name. Place all of the member functions in this file. Then create another source code file, perhaps called 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 cardsHeader.hpp. Then to include the header file in both source code files, place this line at the top:
#include "cardsHeader.hpp"
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++ -Wall -g main.cpp implementation.cpp o cardsProgram
Inside of loadCards(), increment countAndIndex when you load a card, just like normal: countAndIndex++; Notice that loadCards() still returns a value, so you can say how many cards were loaded when control returns back to main(). Dont do any output inside of loadCards (except to prompt the user for the fileName). So loadCards() should return countAndIndex.
Once you have created and implemented your CardCollection class, you will have to instantiate it, or create an object, in the main function. Then you will use the object to call the member functions. See below for an example.
int main()
{
CardCollection myCards;
int count;
count = myCards.loadCards();
cout << Cards loaded: << count;
// the rest of the code here.
// user controlled loop, etc.
// ready for program termination.
myCards.writeCards();
return 0;
}
Notice that I have placed the fileName c-string inside of the class. I did this so that the file name will be accessible to all of the member functions that need it, such as loadCards() and writeCards(). 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 (which is private) in the main function, you will need a getter (accessor) function for it. So the prototype (inside of the class definition) would be:
int getCountAndIndex(); and the header would be:
int CardCollection::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.
You have two options for reading and writing to the same file. The first (simpler) option is to open the file in loadCards using an ifstream, read all the data into memory, and then close the file. At program termination, open the file using an ofstream and the fileName cstring, 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 loadCards(), 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 card 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.
Programming Requirements
You must implement the member functions in an implementation file that is separate from the main function, and you must have a header file. Struct and class definitions and included libraries must be placed in the header file.
You must implement the 6 functions listed in the CardCollection class, but you may create additional member functions if you wish.
Dont use the string library or any of the STL containers such as vectors. Use the
Do not use any global variables (constant globals are OK).
Make sure you check for index out of bounds before adding new data to the array
Check to make sure that the input file is open before reading from it, using ifstream.is_open(). Ask the user to try a different file name if the file does not open or have them type quit to quit the program at that point (if they dont have a collection file).
Make sure that you check for negative numbers and bad data when reading number data from the user.
Dont copy-and-paste any of this code from the document into your code file. If you do, you will have non-ASCII characters in your code file, which will cause errors.
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started