C++ an array of pointers to the base class [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
There are several classes which are made in different files.
Here are the class name: Hospital class and patient class.
Basically, for hospital class, it has array of pointers for patient which can store the information of patient based on their patient type. For patient class(base class) has four derived classes as follows: male, female, inpatient, outpatient. What I am trying to do is, in hospital class, I want to assign the object according to the patient type.
#include <iostream>
#include "Hospital.h"
#include "Female.h"
#include "Male.h"
#include "Inpatient.h"
#include "Outpatient.h"
using namespace std;
Hospital::Hospital(const char * name, int capacity)
{
hospitalName=name;
patientCapacity=capacity;
totalPatients=0;
}
void Hospital::determinePatientType()
{
int selection;
cout << "What is the patient type?" << endl;
cout << "1. Female" << endl;
cout << "2. Male" << endl;
cout << "3. Outpatient" << endl;
cout << "4. Inpatient" << endl;
cin >> selection;
if(selection==1)
{
patients = new Patient[totalPatients];
Female* female = new Female();
patients = female;
}
else if(selection==2)
{
patients = new Patient[totalPatients];
Male* male = new Male();
patients = male;
}
else if(selection==3)
{
patients = new Patient[totalPatients];
Outpatient* outpatient = new Outpatient();
patients = outpatient;
}
else
{
patients = new Patient[totalPatients];
Inpatient* inpatient = new Inpatient();
patients = inpatient;
}
totalPatients++;
}
This is my code, but I am not sure if it's correct or not.
And I will upload the class diagram for your understanding what I am doing.
Thank you for your assistance in advance.
enter image description here

No your code is not correct.
Lets take a look at this code snippet:
if(selection==1)
{
patients = new Patient[totalPatients];
Female* female = new Female();
patients = female;
}
With
patients = new Patient[totalPatients];
you allocate an array of totalPatients objects. You make patients point to the first element of that array.
Then two lines down you do
patients = female;
That reassigns the variable patients to point to the single object female.
You will lose the original memory from the first allocation, which will lead to a leak. It will most likely also lead to undefined behavior if you then use delete[] patients since patients no longer point to an array.
Unless your exercise is to lean how to use pointers and dynamic memory allocation, you should use std::vector.
There's also another potential issue, and that relates toobject slicing and polymorphism (if the classes are polymorphic, i.e. they have virtual member functions).
If you solve the first problem the natural way, by doing e.g.
patients[totalPatients] = female;
Or if you use a std::vector<Patient> and do a simple push_back(female).
Then you slice the female object, and lose all data specific for the Female class. And since you no longer have a Female objects, all virtual functions will think they are called on a Patient object, making polymprphism not working either.
To solve this problem you should have a vector (or array) of pointers to the base Patient class. Like e.g. std::vector<Patient*>.
Or better yet use a smart pointer like std::unique_ptr as in std::vector<std::unique_ptr<Patient>>.

Related

C++: How do I create a collection field for storing a finite number of instances of a class?

I have a problem that requires I track tickets sold at a theatre. To do this I need to create a ShowTicket class. The class should contain a collection field for the rows, seat numbers, and whether the tickets have been sold or not. The class only needs to support 10 sold tickets. Assume a ticket that is not referenced before has a sold status of false.
Member functions must include:
bool is_sold(string row, string seat);
void sell_seat(string row, string seat);
string print_ticket(string row, string seat);
So I made the following class and methods:
class ShowTicket {
string row;
string seat_num;
bool sold;
public:
ShowTicket(string row = "-1",
string seat_num = "-1",
bool sold = false)
:row(row),
seat_num(seat_num),
sold(sold){}
bool is_sold(string new_row, string new_seat_num){return sold;}
void sell_seat(string new_row, string new_seat_num){row = new_row; seat_num = new_seat_num; sold= true;}
string print_ticket(string row, string seat_num) {
string s;
sold ? s = "sold" : s = "available";
return row + " " + seat_num + " " + s;
}
};
I need my main function to look like this:
int main() {
ShowTicket myticket;
if(!myticket.is_sold("AA","101"))
myticket.sell_seat("AA","101");
cout << myticket.print_ticket("AA","101") << endl;
cout << myticket.print_ticket("AA","102") << endl;
return 0;
}
And return:
AA 101 sold
AA 102 available
*This is not required but it is possible to implement this without the 10 object limit. If you have time to include that version as well it would be much appreciated. Thanks to all.
When approaching a problem like this figuring out how many classes are needed and what they represent is one of the keys. Figuring out what the real world object types are can be helpful. So in a theater there are many objects; 1 Theater, potentially multiple viewing rooms, movies, tickets, concession stands, seats and many more. However, in this case you're dealing with three, one theater that's assumed to have only one movie playing in a single viewing room. You also have seats and tickets. But this problem really doesn't do anything with tickets. For instance you are not tracking who has it, who paid for it, what time it's sold. So you really only have two objects of interest a theatre and seats. So you'll need two classes to represent those two real world object. Now a seat doesn't have many theaters in it, but a theater does have many seats. So the theatre will need a collection of seats associated with it. In this case you'll you will also have a ShowTicket class, since that's a given constraint of the problem. Logically the ShowTicket is most closely related to the theatre, since you've been told it should contain a container of seats.
Now what attributes of a seat are interesting in this problem? Whether it reclines? It's price? Who's sitting in it? What row it's in? What's its number in that row? Has the ticket been sold? The answer to those questions. You'll have to decide where and how to store that information within the class. For instance is the seat position going to be represented as a string, like "A101" or is it going to be represented by a row 'A' and a seat 101. And are those values going to be strings, a single character or an integer.
And how are you going to represent sold verses available? Are you going to put available seats in one container class and sold seats in another containers object? Or are you simply going to store a bool in the class indicating sold or not?
There are many ways to code a solution to this problem that will work. And some will be more efficient than others. And some when written in production code, that may be modified over and over again for years will be easier to maintain due to a simple, clear design.
Obviously I'm not providing a concrete solution to your problem. Instead I'm trying to help to provide the thought processes to guide you to solving many programming problems.
Credit to Jerry Jeremiah:
#include <iostream>
#include <string>
#include <map>
class ShowTicket {
using TicketsMap = std::map<std::pair<std::string,std::string>,bool>;
static TicketsMap tickets; // needs to be defined outside the class
public:
bool is_sold(std::string row, std::string seat_num){return tickets[{row,seat_num}];}
void sell_seat(std::string row, std::string seat_num){tickets[{row,seat_num}]=true;}
std::string print_ticket(std::string row, std::string seat_num) {
return row + " " + seat_num + " " + (tickets[{row,seat_num}]?"sold":"available");
}
};
ShowTicket::TicketsMap ShowTicket::tickets;
int main() {
ShowTicket myticket;
if(!myticket.is_sold("AA","101"))
myticket.sell_seat("AA","101");
std::cout << myticket.print_ticket("AA","101") << std::endl;
std::cout << myticket.print_ticket("AA","102") << std::endl;
return 0;
}

Displaying elements of a struct array by using a function [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
So I need to display a table with all of the categories such as housing, transportation, etc along with the other information in each of the arrays that I've initialized. I can't seem tot figure out how to display individual array elements using the "displayTable" function. When I say "cout << housing[0] << " " << utilities[0]" and so on I keep getting a build error. I've tried different syntax as well but I just can't figure it out. It's for an assignment in one of my classes. Any help is much appreciated!
#include <iostream>
#include <iomanip>
using namespace std;
struct Category
{
string category;
double maxAmount;
double amountSpent;
};
void displayTable(Category housing[3], Category utilities[3],
Category transportation[3], Category food[3],
Category entertainment[3], Category miscellaneous[3])
{
cout << setprecision(2)
<< housing[0];
}
int main()
{
int menuChoice;
Category housing = {"Housing", 500.00, 0.00};
Category utilities = {"Utilities", 150.00, 0.00};
Category transportation = {"Transportation", 50.00, 0.00};
Category food = {"Food", 250.00, 0.00};
Category entertainment = {"Entertainment", 150.00, 0.00};
Category miscellaneous = {"Miscellaneous", 50.00, 0.00};
do
{
} while (menuChoice != 3);
return 0;
}
I think you don't study well the array etc. With the string housing[0] you access the first element of an array named housing however in this case there is not array in the code. Maybe you want to create a function that take an element of the type Category and print the value of its field. Something like this:
displayCategory(Category aCategory){
cout<<"Category = "+aCategory.category+"\n"+"maxAmount ="+aCategory.maxAmount+"\n"+"amountSpent = "+aCategory.amountSpent+"\n";
}
Then you maybe want to create an array of Category so instead of declare a variable for every category you could do this:
Category arrayOfCategory[6];
arrayOfCategory[0] = {"Housing", 500.00, 0.00};
arrayOfCategory[1] = {"Utilities", 150.00, 0.00};
arrayOfCategory[2] = {"Transportation", 50.00, 0.00};
arrayOfCategory[3] = {"Food", 250.00, 0.00};
arrayOfCategory[4] = {"Entertainment", 150.00, 0.00};
arrayOfCategory[5] = {"Miscellaneous", 50.00, 0.00};
now if you want a function that print all the category in arrayOfCategory simply using the first function displayCategory we can create this function:
displayTable(Category *anArrayOfCategory, int dimOfTheArray){
for(int i = 0; i < dimOfTheArray; i++)
displayCategory(anArrayOfCategory[i]);
}
void displayTable(Category housing[3], Category utilities[3],
Category transportation[3], Category food[3],
Category entertainment[3], Category miscellaneous[3])
{
std::cout << setprecision(2) << housing[0];
}
housing[0] is of type Category, which you made. How should std::cout know what to print if you give it your own custom type?
You can print the members of your struct one by one like so:
std::cout << setprecision(2) << housing[0].maxAmount;
or implement a custom << operator inside your type:
struct Category
{
std::string category;
double maxAmount;
double amountSpent;
friend std::ostream& operator<< (std::ostream& stream, const Category& category) {
stream << category.maxAmount;
}
};
and then your original code should work fine.
(Obviously you need to add the other members to the output as well, and maybe add some headers/titles, commas etc. for human readability, but the principle should be clear.)
You should treat Category as a struct, not as an array
The simplest way is to access members in the following way
void displayTable(Category housing, Category utilities,
Category transportation, Category food,
Category entertainment, Category miscellaneous)
{
cout << setprecision(2)
<< housing.maxAmount;
}

Intro to classes (c++) project wants us to create two constructors, but neither of them need any parameters - what should i do here?

I think I'm just confused on the wording to this project, but I'm posting here to make sure I have the basics on classes correct (like I said, we just started learning them).
The beginning of the project prompt is as follows:
Declare and define a class called Odometer. This class will have two private variables, one for the miles driven and the other for the gallons of gas pumped into the car.
The member functions should include:
A constructor that takes initial values for both of the private variables.
A default constructor that sets both values to zero.
Along with more member functions that aren't important for my problem. I understand the default constructor fully, but the other is the one I'm having troubles with. If he (my professor) wants us to gather initial variables, then why would it need any parameters at all? I guess I could pass an empty string into it as a parameter, but I feel like there's something I'm missing here...
To expand on the point of this project, in case it's needed, we are creating a program that allows the user to continually enter (on a menu screen) either miles driven or gallons put into their tank. The program will then find the mpg, when the user requests it. Very simple.
Here's part of the program, which should be enough for someone to help me with this. The second/non-default constructor seems like it would work, except obviously I need some type of parameter. Any suggestions or help is greatly appreciated.
#include <iostream>
using namespace std;
class Odometer{
public:
Odometer(); // sets values to 0
Odometer(WHAT GOES HERE); // gathers initial values
void get_miles();
void get_gallons();
void add_in_trip_miles();
void add_gas();
private:
double milesDriven; // represents the miles the car has driven
double gallonsGas; // represents the number of gallons pumped into car
};
int main() {
Odometer userInfo; // creates object for the user-inputted values
bool quit = false; // true when user wants to quit
int userChoice; // for navigating the menu screen
while(!quit){
cout << "To view total miles, enter 1. To view total gallons, enter 2.\nTo record more miles driven, enter 3. To record gallons pumped into the tank, enter 4.\n To view the average MPG, enter 5. To reset the odometer, enter 6.\n To quit the program, enter 7." << endl;
cin >> userChoice;
if(userChoice == 1) userInfo.get_miles(); // TODO: switch/case statement instead?
if(userChoice == 2) userInfo.get_gallons();
if(userChoice == 3) userInfo.add_in_trip_miles(); // TODO: "function which increases the miles by the amount sent in its parameter
}
cout << "Have a nice day!" <<endl;
return 0;
}
Odometer::Odometer(){ // sets values to 0 (default)
milesDriven = 0;
gallonsGas = 0;
}
Odometer::Odometer(WHAT GOES HERE?){ // gathers initial values
cout << "Please enter an initial value for miles driven." << endl;
cin >> milesDriven;
cout << "Please enter an initial value for how many gallons were put into the car." << endl;
cin >> gallonsGas;
}
Your teacher is asking you to implement the second constructor with parameters so user will be able to initialize the object with the state he wants. I would implement it like this:
Odometer(double milesDriven_, double gallonsGas_) :
milesDriven(milesDriven_),
gallonsGas(gallonsGas_)
{}

How to compare a vector to a map [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Okay so I have an inventory class that accesses a static vector from my base class MainShop. I also have a SwordShop class which inherits from MainShop. (Both Inventory and SwordShop are derived classes).
//SwordShop class
void SwordShop::Shop
{
//I have a setter function where it takes an integer and a string and adds its to my hashmap.
//Also have a getter function which has a for loop displaying my items in my map
this->setWeaponSoldier(1, "1) Meito Ichimonji\n +4 Damage\n 150Gold");
this->setWeaponSoldier(2, "2) Shusui\n +10 Damage\n 230Gold");
this->setWeaponSoldier(3, "3) Elixir\n +16 Damage\n 300Gold");
this->setWeaponSoldier(4, "4) Blade of scars\n +24 Damage\n 550Gold");
this->setWeaponSoldier(5, "5) Ragnarok\n +32 Damage\n 610Gold");
this->setWeaponSoldier(6, "6) Eternal Darkness\n +40 Damage\n 690Gold");
this->setWeaponSoldier(7, "7) Masamune\n +52 Damage\n 750Gold");
this->setWeaponSoldier(8, "8) Soul Calibur\n +60 Damage\n 900Gold");
}
//Function in my inventory class
void Inventory::DisplayInventory()
{
int choice;
cout << "\nWhat do you want to do?\n1) Check Status\n2) Equip Weapons\n";//Equip what is in your inventory
cin >> choice;
switch (choice)
{
case 1: this->DisplayStats();
break;
case 2:cout << WeaponInventory.size() << endl;//debug
if (!WeaponInventory.empty())//Make sure inventory is not empty
{
cout << "Your current Weapons are: \n";
for (unsigned int i = 0; i < WeaponInventory.size(); ++i)
cout << i+1 << ") " << WeaponInventory[i] << endl;//cout whats currently in my inventory
cout << "What item weapon would you like to equip?";
/***********Here is the problem*******************/
//how can I make the user choose the actual and correct item in the inventory?
//cin >> equipChoice;
//code goes here
}
else cout << "Error! You currently do not own any items\n";
break;
}
So for example lets say the user adds Meito Ichimonji into my WeaponInventory vector and then adds another one. How can I make the user have the ability to pick the right item? Im looking for something like this:
//PseudoCode
Displays my inventory with for loop
I have two items in it which user buys
1)Meito Ichimonji
and
2)Elixir
cout << "what would you like to equip?";
cin >> equipChoice
if (equipChoice == 1)//chooses whatever item is first
check to see what the attack that the weapon has and add it to my attack
attack += 20;//lets say the sword had 20 attack
else if (equipChoice == 2)//chooses whatever is second
do something else
etc...
Sorry if I have not explained it clearly, but I tried my best!
This is not really an issue of coding/code-design but rather a conceptual design issue. I would propose to start from a blank slate and formalise the design, possibly using a 'relational' perspective, even though you might not use an RDMS in an implementation (or some other formalism like UML) just to put some clear stakes in the ground. At least such model would give a clear view of the relationships between the various entities and help understanding what is needed in order to access/retrieve information from the model. Most likely the code will then be the least you'll have to worry about.

How to store objects for later use and make them searchable

At the moment I am using a vector to store pointers to the object every time one is made, but that feels a little silly. There's probably a better way, but I haven't found it.
What I'm doing: Example usage:
The problem:
If I want to retrieve a certain Date I have to go over all items in the vector to see if RecPaymentsStack.stackDate matches the date the user requested.
The RecPaymentStack is actually completely useless at the moment because what I should be doing, is, when adding a new item, checking if a "RecPaymentStack.stackDate" has already been made for the new item's Date property, and if so add the new pointer to "RecPayments" to an array of pointers inside the "RecPaymentStack" object. But how?
I'm probably unnecessarily complicating things (something I do a lot) so an explenation on how something like this should be done would be very nice.
Detailed info: (in case I was being too vague)
The below example is supposed to resemble a calendar that can hold certain items (RecPayments) and those items are grouped by their date (RecPaymentsStack).
struct RecPayments
{
std::string name;
Date* date;
float cost;
};
struct RecPaymentsStack
{
Date* stackDate; //This stack's date
RecPayments * thePaymentItem; //Hold pointer to the actual item
};
And here's how I'm currently storing them
std::vector<RecPaymentsStack*> RecPaymentsVector; //This vector will hold pointers to all the Recurring Payments
void addRecurring(std::string theDate,std::string theName,float theCost)
{
//New recurring payment
RecPayments * newPaymentItem = new RecPayments;
//Set recurring payment properties
newPaymentItem->name = theName;
newPaymentItem->date = new Date(stringToChar(theDate));
newPaymentItem->cost = theCost;
//Add recurring payment to stack
RecPaymentsStack * addToStack = new RecPaymentsStack;
addToStack->stackDate = new Date(stringToChar(theDate));
addToStack->thePaymentItem = newPaymentItem;
//Add pointer to RecPaymentsStack to vector
RecPaymentsVector.push_back(addToStack);
}
So to retrieve the items for a given date, I am currently going over all pointers in the vector to see if the "stackDate" property matches the requested date, and if so I use the "thePaymentItem" property to show the actual item.
void getItemsNow(Date requestedDate)
{
std::cout << "Showing Dates for " << requestedDate << std::endl;
unsigned int i;
for(i=0;i<RecPaymentsVector.size();i++) //Go over all items in vector
{
Date dateInVector(*RecPaymentsVector[i]->stackDate); //Get the date from the vector
if(dateInVector == requestedDate) //See if Date matches what the user requested
{
//Date matched, show user the item properties.
std::cout << "Date: " << dateInVector <<
" has name: " << RecPaymentsVector[i]->thePaymentItem->name <<
" and price " << RecPaymentsVector[i]->thePaymentItem->cost <<
std::endl;
}
}
}
3 problems with this:
Going over all items in the vector is highly inefficient if I only
need a couple of pointers
The RecPaymentStack is actually completely useless at the moment because what I should be doing, is, when adding a new item, checking if a "RecPaymentStack.stackDate" has already been made for the new item's Date property, and if so add the new pointer to "RecPayments" to an array of pointers inside the "RecPaymentStack" object. But how?
All of this feels extremely silly to begin with.. there's probably a much easier/professional way to do this but I can't find out what, probably because I'm still thinking like a PHPer.
So the general idea here is that I end up doing something like (silly example)
for each RecPaymentsStack->stackDate //For each unique Date, show it's children items.
{
cout << "The Date is " CurrentRecPaymentsStack->stackDate and it holds the following items:
for each CurrentRecPaymentsStack->thePaymentItem //This would now be an array of pointers
{
cout << "item name " CurrentRecPaymentsStack->thePaymentItem->name << " with cost " << CurrentRecPaymentsStack->thePaymentItem->cost << endl;
}
}
Which would basically go over all the unique "RecPaymentsStack" objects (unique determined by it's "Date" property) and for each Date it would then show it's "children" from the RecPayments struct.
And there has to be some way to search for a particular date without having to go over all the available ones.
Rather than using a vector to manage your items, you should replace your RecPaymentsStack instance with a std::multimap. The key type is your Date structure, the value type is RecPayments (which I would change to the singular form RecPayment). Small example (untested):
typedef std::multimap<Date, RecPayment> RecPaymentsByDateMap;
typedef std::pair<RecPaymentsByDateMap::iterator,
RecPaymentsByDateMap::iterator>
RecPaymentsByDateMapIters;
RecPaymentsByDateMap payments_by_date;
RecPaymentsByDateMapIters findByDate(Date date) {
return payments_by_date.equal_range(date);
}
...
// find all payments with the given date
RecPaymentsByDateMapIters iters = findByDate(...);
for (RecPaymentsByDateMap::iterator it = iters.first;
it != iters.second;
++it)
{
std::cout << "Payment " << it->second.name << std::endl;
}
I might design it like this -- this is just a loose idea, details should be adjusted according to your requirements:
#include <deque>
#include <map>
#include <string>
struct RecPayment
{
std::string name;
Date date;
float cost;
};
struct RecPaymentsStack
{
Date stackDate;
std::deque<RecPayment> thePaymentItem;
bool operator<(RecPaymentsStack const & rhs) const
{
return stackDate < rhs.stackDate;
}
explicit RecPaymentsStack(Date const & d) : stackDate(d) { }
};
typedef std::multimap<RecPaymentsStack> PaymentsCollection;
Now you can insert elements:
PaymentsCollection payments;
{
auto it = payments.emplace(Date("..."));
it->thePaymentItem.emplace_back(Payment{name1, date1, cost1});
it->thePaymentItem.emplace_back(Payment{name2, date2, cost2});
it->thePaymentItem.emplace_back(Payment{name3, date3, cost3});
}