How can I use struct efficiently in my quiz? - c++

I'm trying to create a simple quiz with struct. But my program here is very repetitive. How can I modify it and make it more efficient? Especially to check if the answers are correct I do not want to declare a separate variable and store it as int correct. Thank You.
#include <iostream>
using namespace std;
struct Quiz{
string question;
string answers[3];
};
struct Quiz2{
string question2;
string answers2[3];
};
int correct;
int main()
{
Quiz Question;
Question.question = "What is the smallest county?";
cout << Question.question << endl;
Question.answers[0] = "1. USA";
cout << Question.answers[0] << endl;
Question.answers[1] = "2. India";
cout << Question.answers[1] << endl;
Question.answers[2] = "3. Vatican City";
cout << Question.answers[2] << endl;
cout << endl;
cout << "Choose 1-3: ";
cin >> correct;
if(correct == 3)
cout << "Correct!";
else
cout << "Incorrect!";
cout << endl;
cout << endl;
// Question 2
Quiz2 Question2;
Question2.question2 = "What is the biggest animal in the world?";
cout << Question2.question2 << endl;
Question2.answers2[0] = "1. Elephant";
cout << Question2.answers2[0] << endl;
Question2.answers2[1] = "2. Blue Whale";
cout << Question2.answers2[1] << endl;
Question2.answers2[2] = "3. Great white shark";
cout << Question2.answers2[2] << endl;
cout << endl;
cout << "Choose 1-3: ";
cin >> correct;
if(correct == 2)
cout << "Correct!";
else
cout << "Incorrect!";
return 0;
}

That's as much as non-repetitive as I can imagine after a few minutes of thinking. Maybe it can become smaller, but for my taste this looks alright.
You basically rely on std::vector class, instead of a typical array, because vectors can be of dynamic size. This allows us to use only one struct, but make as many answers as we want (3, 5, 10, whatever). We then create the whole quiz as another vector of questions. We're only left with printing to the console - for that we use loops, as our quiz structure is very simple and self-repetitive.
#include <iostream>
#include <vector>
using namespace std;
struct Question{
string question;
int correct_idx;
vector<string> answers;
Question(string question, int correct_idx, vector<string> answers)
:question(question), correct_idx(correct_idx), answers(answers)
{}
};
int main()
{
vector<Question> whole_quiz = {
Question{
"What is the smallest country?",
2, // indexes start from 0, e.g. 0, 1, 2. So 2 is correct
{"USA", "India", "Vatican City"}
},
Question{
"What is the biggest animal in the world?",
1,
{"Elephant", "Blue Whale", "Great white shark"}
},
};
for(auto question : whole_quiz) {
cout << question.question << endl;
for(int i = 0; i < question.answers.size(); ++i) {
cout << i+1 << ". " << question.answers[i] << endl;
}
cout << "Choose 1-" << question.answers.size() << endl << endl;
int guess;
cin >> guess;
if (guess-1 == question.correct_idx) {
cout << "Correct!" << endl << endl;
} else {
cout << "Incorrect!" << endl << endl;
}
}
return 0;
}

I would propose a more complicated, but also a more fun solution. Have a huge list of answers, like 100, or 1000, or as many as you like. Then in your struct have a std::string question, and std::vector<int> possible answers that are indexes in the huge list. First answer in the list is the correct one. So when you ask a question you pick first index, and three more indexes at random, and you shuffle them up, and present this to the user. The quiz will be different every time.

struct acts as a template, not a single variable. so there's no need to create 2 different struct. Also, a correct variable can be added to the struct for ease of checking.
Code (I split it into different functions for clearer understanding):
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct quiz
{
int correct;
string question;
vector<string> answers;
};
vector<quiz> questionsToAsk;
void addNewQuestion(string ques, vector<string>ans, int cor)
{
quiz q1;
q1.question = ques;
q1.answers = ans;
q1.correct = cor;
questionsToAsk.push_back(q1);
}
void displayQuestion(int idx)
{
quiz cur = questionsToAsk[idx];
cout << cur.question << '\n';
for (int i = 0; i < cur.answers.size(); i++)
{
cout << cur.answers[i] << '\n';
}
cout << "Choose 1-3: "; int inp; cin >> inp;
if (inp == cur.correct) {cout << "Correct";} else {cout << "Incorrect";} cout << '\n';
}
int main()
{
vector<string> ans1({"1. USA", "2. India", "3. Vatican City"});
vector<string> ans2({"1. Elephant", "2. Blue Whale", "3. Great white shark"});
addNewQuestion("What is the smallest county?", ans1, 3);
addNewQuestion("What is the biggest animal in the world?", ans2, 2);
for (int i = 0; i < questionsToAsk.size(); i++)
{
displayQuestion(i);
}
}
Result:
What is the smallest county?
1. USA
2. India
3. Vatican City
Choose 1-3: 1
Incorrect
What is the biggest animal in the world?
1. Elephant
2. Blue Whale
3. Great white shark
Choose 1-3: 2
Correct

You can use a template like
<typename T = int>
T get_answer(std::istream& in) {
T res;
in >> res;
return res;
}
...
if(get_answer(std::cin) == 3)
cout << "Correct!";
else
cout << "Incorrect!";
You can also overload operator<<.
#include <iostream>
#include <string>
template<typename T = int>
T get_answer(std::istream& in) {
T res;
in >> res;
return res;
}
class Quiz{
public:
Quiz(const std::string& q, const std::string& a1, const std::string& a2, const std::string& a3, unsigned correct)
: question(q), answers{a1, a2, a3}{
CheckAnswer(correct);
}
friend std::ostream& operator<<(std::ostream& os, const Quiz& quiz) {
os << quiz.question << "\n";
unsigned i = 1;
for (const auto & answer : quiz.answers) {
os << i++ << ". " << answer << "\n";
}
os << "\n";
return os;
}
void CheckAnswer(unsigned correct) {
std::cout << *this << "Choose 1-3: ";
if(get_answer(std::cin) == correct)
std::cout << "Correct!";
else
std::cout << "Incorrect!";
std::cout << std::endl;
std::cout << std::endl;
}
private:
std::string question;
std::string answers[3];
};
int main()
{
Quiz Question("What is the smallest county?", "USA", "India", "Vatican City", 3);
// Question 2
Quiz Question2("What is the biggest animal in the world?", "Elephant", "Blue Whale", "Great white shark", 2);
return 0;
}

The only thing you can do is define the correct variable in the struct itself. You can use a loop for decreasing the repetitiveness but obviously the question and the answers will have to be stored, it cannot be simplified further.

Related

Sorting a Class [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 1 year ago.
Improve this question
So, I am learning about classes in C++, I created two classes, one for a University that contains a list of class Students, i managed to create students, and introduce some values to the classes, but now i want to sort the class students by student number, i tryed using the sort function, but im not succeeding. I will leave my code bellow, please give some good tips and advises, so I can improve my code. thanks
main.css
#include <iostream>
#include "university.h"
#include "students.h"
using namespace std;
int main() {
university univ = university();
return 0;
}
university.h
#pragma once
#include <iostream>
#include <string>
#include <list>
#include <algorithm>
#include "students.h"
using namespace std;
class university
{
private:
list<students> lstudents;
list<students>::iterator itstudents;
public:
university();
void setStudents(list<students> lstudents);
void registerStudent();
void list();
void average();
//void sortstudents();
};
university.cpp
#include "university.h"
using namespace std;
university::university() { //constructor
string resp = "s";
int op;
bool out = true;
cout << "Enter Students:" << endl;
while (resp != "n")
{
this->registerStudent();
cout << "Continue inserting? (s/n)" << endl;
cin >> out;
cin.ignore();
}
while (out)
{
cout << "What you Want to do? (1- List Students 2- Sudent Average 3- Sort Students by Number 4- Leave)" << endl;
cin >> op;
switch (op)
{
case 1:
this->list();
break;
case 2:
this->average();
break;
/*case 3:
this->sortStudents();
break;*/
case 4:
out = false;
break;
};
}
}
void university::setStudents(list<students> lstudents) {
this->lstudents = lstudents;
}
void university::registerStudent()
{
lstudents.push_back(students());
}
void university::list()
{
int sum = 0;
cout << "------------------------- LIST STUDENTS -------------------------------\n\n";
cout << left << setw(11) << "Number"
<< left << setw(30) << "Name"
<< left << setw(30) << "Course"
<< left << setw(10) << "Average";
cout << "\n";
for (itstudents = lstudents.begin(); itstudents != lstudents.end(); itstudents++)
{
(*itstudents).list();
++sum;
}
//cout << "Total de pacientes:" << somatorio << endl;
//somatorio = 0;
}
void university::average()
{
int sum = 0;
double average = 0;
for (itstudents = lstudents.begin(); itstudents != lstudents.end(); itstudents++)
{
average += (*itstudents).getaverage();
++sum;
}
cout << "Average:" << average / sum << endl;
}
//void university::sortstudents() {
// sort(lstudents.begin(), lstudents.end(), &students::compare);
//}
students.h
as you can see the commented code is my attempts on sorting the class student my number
#pragma once
#include <iomanip>
#include <algorithm>
#include <list>
#include "university.h"
using namespace std;
class students {
private:
std::string name;
std::string course;
int number;
double average;
public:
//friend bool operator<(estudantes& left,estudantes& right) { return left.matricula < right.matricula; };
students();
void list();
double getaverage();
int getnumber();
//bool compare(estudantes a, estudantes b);
};
students.cpp
#include "students.h"
students::students() {
cout << "Name: ";
getline(cin, name);
cout << "Course: ";
getline(cin, course);
cout << "Number: ";
cin >> this->number;
cout << "Average: ";
cin >> this->average;
}
void students::list() {
cout << left << setw(11) << number;
cout << left << setw(30) << name;
cout << left << setw(30) << course;
cout << left << setw(10) << average << endl;
}
double students::getaverage() {
return average;
}
int students::getnumber() {
return number;
}
//bool estudantes::compare(student a, student b) {
//
// if (a.number < b.number)
// return 1;
// else
// return 0;
//}
Made it selfcontained and fixed. I'll post and then aexplain as surely people will have closed the question too soon:
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <list>
#include <string>
class students {
private:
std::string name;
std::string course;
int number;
double average;
public:
// friend bool operator<(students& left,students& right) { return
// left.matricula < right.matricula; };
students();
void list();
double getaverage();
int getnumber();
static bool compare(students const& a, students const& b);
};
students::students()
{
std::cout << "Name: "; getline(std::cin, name);
std::cout << "Course: "; getline(std::cin, course);
std::cout << "Number: "; std::cin >> this->number;
std::cout << "Average: "; std::cin >> this->average;
}
void students::list() {
std::cout << std::left << std::setw(11) << number;
std::cout << std::left << std::setw(30) << name;
std::cout << std::left << std::setw(30) << course;
std::cout << std::left << std::setw(10) << average << std::endl;
}
double students::getaverage() {
return average;
}
int students::getnumber() {
return number;
}
bool students::compare(students const& a, students const& b) {
return a.number > b.number;
}
class university {
private:
std::list<students> lstudents;
std::list<students>::iterator itstudents;
public:
university();
void setStudents(std::list<students> lstudents);
void registerStudent();
void list();
void average();
void sortStudents();
};
university::university() // constructor
{
std::string resp = "s";
int op;
bool out = true;
std::cout << "Enter Students:" << std::endl;
while (resp != "n") {
this->registerStudent();
std::cout << "Continue inserting? (s/n)" << std::endl;
std::cin >> out;
std::cin.ignore();
}
while (out) {
std::cout << "What you Want to do? (1- List Students 2- Sudent Average "
"3- Sort Students by Number 4- Leave)"
<< std::endl;
std::cin >> op;
switch (op) {
case 1: this->list(); break;
case 2:
this->average();
break;
case 3: this->sortStudents(); break;
case 4: out = false; break;
};
}
}
void university::setStudents(std::list<students> lstudents) {
this->lstudents = lstudents;
}
void university::registerStudent()
{
lstudents.push_back(students());
}
void university::list()
{
int sum = 0;
std::cout << "------------------------- LIST STUDENTS -------------------------------\n\n";
std::cout << std::left << std::setw(11) << "Number"
<< std::left << std::setw(30) << "Name"
<< std::left << std::setw(30) << "Course"
<< std::left << std::setw(10) << "Average";
std::cout << "\n";
for (itstudents = lstudents.begin(); itstudents != lstudents.end(); itstudents++)
{
(*itstudents).list();
++sum;
}
//std::cout << "Total de pacientes:" << somatorio << std::endl;
//somatorio = 0;
}
void university::average()
{
int sum = 0;
double average = 0;
for (itstudents = lstudents.begin(); itstudents != lstudents.end(); itstudents++)
{
average += (*itstudents).getaverage();
++sum;
}
std::cout << "Average:" << average / sum << std::endl;
}
void university::sortStudents() {
lstudents.sort(&students::compare);
}
int main() {
university univ = university();
return 0;
}
Explanation
There were a number of issues.
students::compare was a non-static member function, meaning it can only be called on an instance of student. To have a 2-argument sort predicate as required, simply making it static can work
The implementation could be much more idiomatic:
bool students::compare(students const& a, students const& b) {
return a.number > b.number;
}
That avoids the C-ism of using 1 as if it were true, and the useless if/else
You used std::sort but it requires random access iterators. std::list doesn't provide that. For that reason std::list::sort exists:
void university::sortStudents() {
lstudents.sort(&students::compare);
}
Among many other style issues:
don't using namespace std;
don't do side-effects in constructors?
error-check IO
avoid division by zero (e.g. in average()

Array, avoid pulling Duplicates, simple code, C++

Its a card game, I draw 2 cards from the deck (the array) with the help of two functions.
Each element of the array represent one card with a symbol Spades, Hearts, Diamonds or Clubs.
These numbers in the array \5 \4 \3 \6, represent Clubs, Dimaond, Heatrs, spades (just if ur curious)
The problem!
When I draw a card two times I sometimes get Duplicates.. The same card twice.
How do I make sure the same card cant be drawn twice?
How do I avoid getting duplicates??
This is how the code Looks like.
Some INFO about the array...
The further in, in the array, the higher value the element has.
I have shortened the array... for easy testing of a solution... later the array will be 52 elements.
array<string, 3> cards = { "Ess \5", "Ess \4", "Ess \3" };
//The function.
pair<string, int> draw_card()
{
int random_index = rand() % 52;
string card = cards[random_index];
return { card, random_index };
}
int main()
{
// Seed, random.
srand((unsigned int)time(NULL));
// Calling the function 2 times.
pair<string, int> you_drew = draw_card();
cout << "You drew: " << you_drew.first << endl;
pair<string, int> comp_drew = draw_card();
cout << "Computer drew: " << comp_drew.first << endl;
// Deciding the winner.
int your_score{ 0 };
int the_computers_score{ 0 };
if (you_drew.second > comp_drew.second) {
cout << "You Won!" << endl;
your_score++;
}
else if (you_drew.second < comp_drew.second) {
cout << "You Lost!" << endl;
the_computers_score++;
}
return 0;
}
Everything is working fine, EXCEPT sometimes I get duplicates... I want to make sure I can Not get that...
Somehow when I draw a card the element in the array should not be able to be drawn.. I want to avoid getting duplicates. Please help me!
Shouldnt something like this work? its not but.. shouldnt it?
pair<string, int> comp_drew = draw_card();
if (you_drew == comp_drew) {
bool run8 = true;
while (run8) {
pair<string, int> comp_drew = draw_card();
if (comp_drew != you_drew) {
cout << "Computer drew: " << comp_drew.first << endl;
run8 = false;
}
}
}
Or maybe another solution..
Perhaps after calling the function one time i can delete the return index from the array?
You can swap the drawn card to the end and only choose an index smaller than 51 the next time.
int array_len = 52; // global variables are not great, but it's easier here
pair<string, int> draw_card()
{
int random_index = rand() % array_len;
--array_len;
string card = cards[random_index];
std::swap(cards[random_index], cards[array_len]);
return { card, random_index };
}
There are many different ways to do this.
std::random_shuffle
#include <iostream>
#include <algorithm>
using namespace std;
class CardMachine {
static unsigned constexpr DECK_SIZE = 4;
int cards[DECK_SIZE] = {1,2,3,4};
int lastUsedCardIndex = -1;
public:
int getCard() {
if (lastUsedCardIndex == DECK_SIZE - 1)
shuffle();
return cards[++lastUsedCardIndex];
}
void shuffle() {
random_shuffle(begin(cards), end(cards));
}
};
int main()
{
CardMachine cardMachine = CardMachine();
cout << "unhsuffled - 1,2,3,4 without duplicates:" << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << "Shuffled. Random order, and still no duplicates:" << endl;
cardMachine.shuffle(); // or call getCard which can shuffle
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
return EXIT_SUCCESS;
}
Mark Card as Taken
#include <iostream>
#include <random>
using namespace std;
class CardMachine {
static unsigned constexpr DECK_SIZE = 4;
inline static int constexpr cards[DECK_SIZE] = {1,2,3,4};
bool cardIsGone[DECK_SIZE] = {false, false, false, false};
public:
int getCard() {
while(true) {
int const RANDOM_INDEX = rand()%DECK_SIZE;
if(!cardIsGone[RANDOM_INDEX]) {
cardIsGone[RANDOM_INDEX] = true;
return cards[RANDOM_INDEX];
}
}
}
void shuffle() {
for(bool &isGone : cardIsGone)
isGone = false;
lastUsedCardIndex = -1;
}
};
int main()
{
CardMachine cardMachine = CardMachine();
cout << "Shuffled - Random order, and still no duplicates:" << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << "Shuffled. Random order, and still no duplicates:" << endl;
cardMachine.shuffle(); // Causes infinite loop if you call getCard DECK_SIZE + 1 times
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
return EXIT_SUCCESS;
}
It's not the most efficient solution, but with small values like 52, it should be instant.
Swap Used Cards to Back and Keep Track of Range
#include <iostream>
#include <random>
using namespace std;
class CardMachine {
static unsigned constexpr DECK_SIZE = 4;
int cards[DECK_SIZE] = {1,2,3,4};
int lastCardIndexExlusive = DECK_SIZE;
public:
int getCard() {
int const RANDOM_INDEX = rand()%lastCardIndexExlusive;
swap(cards[RANDOM_INDEX],cards[lastCardIndexExlusive - 1]);
return cards[--lastCardIndexExlusive];
}
void shuffle() {
lastCardIndexExlusive = DECK_SIZE;
}
};
int main()
{
CardMachine cardMachine = CardMachine();
cout << "Shuffled - Random order, and still no duplicates:" << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << "Shuffled. Random order, and still no duplicates:" << endl;
cardMachine.shuffle(); // Causes exception if getCard DECK_SIZE + 1 times
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
return EXIT_SUCCESS;
}
Remember Last Card
#include <iostream>
#include <random>
using namespace std;
class CardMachine {
static unsigned constexpr DECK_SIZE = 4;
int cards[DECK_SIZE] = {1,2,3,4};
int lastCard = -1;
public:
int getCard() {
int const RANDOM_INDEX = rand()%DECK_SIZE;
if (lastCard == RANDOM_INDEX) {
return getCard();
}
lastCard = cards[RANDOM_INDEX];
return lastCard;
}
void shuffle() {
lastCard = -1;
}
};
int main()
{
CardMachine cardMachine = CardMachine();
cout << "Shuffled - Random order, and still no duplicates, but only able to produce 2:" << endl;
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
cout << "Shuffled. Random order, and still no duplicates:" << endl;
cardMachine.shuffle(); // Causes potential duplicates if getCards 3+ times
cout << cardMachine.getCard() << endl;
cout << cardMachine.getCard() << endl;
return EXIT_SUCCESS;
}
All of these solutions make use of a class to hold state for use in getCard to make sure we get the right behavior.

Accessing multiple instances of a class in C++

I am creating a menu for a restaurant that can have 5 dishes of each category. So far I have created a class for meat dishes and I'm able to add up to 5 dishes, each with a unique identifier. What I am having trouble with is accessing the objects after they have been created.
(There will be multiple categories hence why there is a switch statement with only one case so far).
For example, how would I implement a way to change the description of the second dish?
Here is my code so far:
meat.h
class Meat{
private:
int meatNumber;
std::string meatCategory;
std::string meatDescription[MAX_ITEMS];
double meatPrice[MAX_ITEMS];
public:
Meat();
//setter functions
int setMeatNumber();
std::string setMeatDescription();
double setMeatPrice();
//getter functions
int getMeatNumber();
std::string getMeatCategory();
std::string getMeatDescription(int i);
double getMeatPrice(int i);
};
meat.cpp
#include "Meat.h"
//constructor
Meat::Meat() {
meatNumber = 0;
meatCategory = "Meat";
meatDescription[MAX_ITEMS] = "No description written.";
meatPrice[MAX_ITEMS] = 0.0;
}
//setter functions
int Meat::setMeatNumber(){
static int counter = 1;
meatNumber = counter++;
}
std::string Meat::setMeatDescription(){
int i = 0;
std::cout << "Please enter a short description: " << std::endl;
std::cin >> meatDescription[i];
return meatDescription[i];
}
double Meat::setMeatPrice(){
int i = 0;
std::cout << "Please set the price in a 00.00 format: " << std::endl;
std::cout << "£";
while(!(std::cin >> meatPrice[i])){
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Error. Please enter a number: ";
}
return meatPrice[i];
}
//getter functions
int Meat::getMeatNumber() { return meatNumber; }
std::string Meat::getMeatCategory() { return meatCategory; }
std::string Meat::getMeatDescription(int i) {return meatDescription[i]; }
double Meat::getMeatPrice(int i) { return meatPrice[i]; }
main.cpp
#include <iostream>
#include "Meat.h"
int main() {
int choice;
std::cout << "Menu Creation Terminal\n\n" << std::endl;
std::cout << "\t Welcome\nto Wrapid™ Restaurants\n\n" << std::endl;
std::cout << "1. Add Meat Dish\n2. Add Fish Dish\n3. Add Vegetarian Dish\n4. Add Drink\n"
"5. Edit Current Menu\n6. Quit\n\n" << std::endl;
std::cout << "Please select an option: ";
std::cin >> choice;
switch (choice) {
case 1:
{
int option = true;
int count = 0, i;
Meat meatDish;
std::cout << "Meat Dishes" << std::endl;
while (true) {
meatDish.setMeatNumber();
meatDish.setMeatDescription();
meatDish.setMeatPrice();
//functions to add details to dish
std::cout << "You have added the following dish: " << std::endl;
std::cout << "Item number: \n" << meatDish.getMeatNumber() << std::endl;
std::cout << "Item Category: \n " << meatDish.getMeatCategory() << std::endl;
std::cout << "Item Description: \n" << meatDish.getMeatDescription(i) << std::endl;
std::cout << "Item Price: \n £" << meatDish.getMeatPrice(i) << std::endl;
std::cout << "Would you like to add another item? Press 1 for yes or 2 for no: " << std::endl;
std::cin >> option;
count += 1;
if (count == 5) {
std::cout << "Error. Exceeded maximum items.";
break;
} //breaks out of loop if more than 5 items
if (option == 2) { break; } //breaks out of loop when user is finished adding items
}//while loop to contain menu
}//brace for scope of case 1
}
return 0;
}
As you are using c++ class Meat you can use [] to instantiate N items
for example 5 objects
Meat meats[5];
If you want to modify 2nd object then
meats[1].setMeatDescription(<pass argument>);
You need to change that method using this keyword
this->meatDescription = <pass argument>;
No need to create meatDescription[] as an array
use this code https://pastebin.com/bCkzbFZV you can use meats[i].getMeatDescription()
You could create a new class called DishesContainer. This class could have :
a private std::vector => it will hold every instance
a public function to create a new dish
a public function to change any type of value inside a dish meat.
For exemple to change the description
class DishContainer{
public:
void ChangeDescription(int indexMeat, std::string newDescription){
meats_[indexMeat].setMeatDescription(newDescription);
}
private:
std::vector<Meat> meats_;
}

vector<string> in a struct doesn't work properly

I declared a vector<string> and I cannot even compile it. I tried many ways but none of them worked.
I'm trying to write out the x.surname.push_back(word)[i] but it's definetly written wrongly and I have no idea how to write it properly and make it possible to compile.
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
int main() {
int number, i = 0;
string word;
struct donators {
vector<string> surname;
vector<int> amount;
} x;
cout << "How many donators do you want to register? " << endl;
cin >> number;
for (i = 0; i < number; i++) {
cout << "Surname: ";
cin >> word;
x.surname.push_back(word)[i];
cout << "Amount: ";
x.amount.push_back(i);
cin >> x.amount[i];
}
cout << "OUR GORGEUS DONATORS: " << endl;
for (i = 0; i < number; i++) {
if (x.amount[i] >= 10000) {
cout << "Surname: " << x.surname(word)[i];
cout << "Amount: " << x.amount[i] << endl;
}
else if (x.amount[i] < 10000) {
cout << "Lack of surnames!" << endl;
}
}
cout << "OUR CASUAL DONATORS: " << endl;
for (i = 0; i < number; i++) {
if (x.amount[i] < 10000) {
cout << "Surname: " << x.surname(word)[i];
cout << "Amount: " << x.amount[i] << endl;
} else if (x.amount[i] >= 10000) {
cout << "Lack of surnames!" << endl;
}
}
return 0;
}
And one more thing. How to make sentence "Lack of surnames!" to be written out once? In some cases, it is written out twice or more times what is redundant.
You are putting [i] at seemingly random places in your code. Such as in x.surname.push_back(word)[i];. Don't add things like this to your code if you're unsure about what they're doing.
The x.surname(word)[i] construct are also wrong. What's x.surname(word) supposed to be? This syntax is for function calls. surname, however, is not a function. It's a std::vector<std::string>. Just put x.surname[i] instead.
And one more thing. How to make sentence "Lack of surnames!" to be
written out once? In some cases, it is written out twice or more times
what is redundant.
That's because you write it for every donor that doesn't fit the criterion. Instead, keep track if any donor fits the criterion and only print it when none ends up fitting. You can do it like this:
bool HasGorgeousDonators = false;
And then in the loop:
if (x.amount[i] >= 10000)
{
cout << "Surname: " << x.surname[i];
cout << "Amount: " << x.amount[i] << endl;
HasGorgeousDonators = true;
}
And after the loop:
if (!HasGorgeousDonators)
cout << "Lack of surnames!" << endl;
Likewise for the other loop. Also, please consider the following Q&A:
Why is "using namespace std;" considered bad practice?
It seems like you are writing C with some C++ help functions. However C++ is a different language. Sure, it supports some C structures, but there's so much more.
Take a look at some of my suggestions for implementation and compare it to your code:
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
template<typename T>
T ReadCin(std::string_view const& sv = "") {
T retVal;
if (!sv.empty()) std::cout << sv;
std::cin >> retVal;
return retVal;
}
class Donator {
private:
std::string surname{};
int amount{};
public:
constexpr bool IsGenerous() const noexcept { return amount >= 10000; }
void Read() noexcept {
surname = ReadCin<decltype(surname)>("Surname: ");
amount = ReadCin<decltype(amount)>("Amount: ");
}
friend std::ostream& operator<<(std::ostream& out, Donator const& donator) noexcept {
out << "Surname: " << donator.surname << ", " << "Amount: " << donator.amount;
return out;
}
};
int main() {
std::vector<Donator> donators(ReadCin<int>("How many donators do you want to register?\n"));
for (auto& donator : donators) donator.Read();
std::cout << "OUR GENEROUS DONATORS:\n";
std::copy_if(std::cbegin(donators), std::cend(donators), std::ostream_iterator<Donator>(std::cout, "\n"),
[](Donator const& donator) { return donator.IsGenerous(); });
std::cout << "OUR CASUAL DONATORS:\n";
for (auto const& donator : donators) if (!donator.IsGenerous()) std::cout << donator << '\n'; //alternative
}
I tried to include some of the possibilities using C++. I would really advise you to get a good book on C++.

Setting a string value to none when a class related to it is deleted

I need help with something which I believe is simple. I can assign a student to a project. But when I delete the project, the student is still keeping the project name. I'm thinking of just renaming it back to "None" but I have no idea on how to do that. Help?
Edit
map<int, Student> mstore and vector<int> storeid added.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <map>
using namespace std;
class Human {
public:
virtual void print() const = 0;
};
class Student : public Human {
protected:
string studname;
int studId;
string project;
public:
Student();
Student (string studname, int studId) : studname("Unknown"), studId(0), project("None")
{
cout << "A student is created: Name = " << studname
<< ". Id = " << studId << endl;
}
virtual void print() const {
cout << "Name = " << studname << ". Id = " << studId << ". Project = " << project <<endl; }
void setSName (string sname) { studname = sname; }
void setSID (int sID) { studId = sID; }
void printStudentInfo() const;
void printStudentInfoline() const;
};
void Student::printStudentInfo() const
{
cout << "\nStudent name: " << studname << endl;
cout << "Student ID: " << studId << endl;
cout << "Project: " << project << endl;
}
void Student::printStudentInfoline() const
{
cout << studId << ", " << studname << ", " << project << endl;
}
class Project {
protected:
string projname;
public:
vector <Student> students;
vector <int> storeid;
Project (string projname) : projname(projname) { cout << "Project " << projname << " created" << endl;}
void setPName (string projname) { this->projname = projname; }
void add (int& sid)
{
//student.setProject (projname);
storeid.push_back(sid);
}
int returnid(int& a)
{
return storeid[a];
}
int returnsize()
{ return storeid.size(); }
void printproj() const {
cout << endl << projname << " list: \n";
cout << "Student(s) : " << endl;
for (int i = 0; i < storeid.size(); i++){
cout << storeid[i] << endl;
}
}
void printprojname() const {
cout << projname << endl;
}
};
int main() {
string StudentName;
string ProjectName;
int Studentid;
Student *s1;
Project *p1;
vector<Student> store;
vector<Project> projstore;
map<int, Student> mstore;
map<int, Student>::const_iterator itr;
for (int n=0; n<3; n++) //loop to create 3 students
{
cout <<"Enter name : ";
getline(cin, StudentName);
cout <<"Enter ID : ";
cin >> Studentid;
s1 = new Student(StudentName, Studentid);
s1->setSName(StudentName);
s1->setSID(Studentid);
store.push_back(*s1);
mstore.insert(make_pair(Studentid, *s1));
cin.get();
}
//print map
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfo();
//itr=mstore.begin()+2;
//itr.print();
cout << "Enter project name: ";
getline(cin, ProjectName);
p1 = new Project(ProjectName);
p1->setPName(ProjectName);
//Assigning student to project
cout << endl;
cout << "How many students? :" ;
int y;
cin >> y;
for ( int i = 0; i < y; i++){
cout << "Who would you like to add to this project?" << endl;
int x = 1;
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfoline();
int insID;
cout << "Enter ID number: ";
cin >> insID;
p1->add(insID);
/*
for ( it = store.begin(); it != store.end(); ++it ) {
// For each friend, print out their info
cout << x << ". ";
it->printStudentInfoline();
x++;
}
x = 1;
int insS;
cout << "Enter number: ";
cin >> insS;
p1->add(store[(insS-1)]); //stores selected student into the object
*/
cout << "\nAdding Student done\n" << endl;
}
projstore.push_back(*p1);
//Mstore finds for related ids and displays them accordingly
cout << "print project"<< endl;
vector<Project>::iterator pt;
for ( pt = projstore.begin(); pt != projstore.end(); ++pt ) {
pt->returnsize();
for (int i=0; i <pt->returnsize(); i++){
cout << pt->returnid(i) << endl;
itr=mstore.find(pt->returnid(i));
itr->second.printStudentInfo();
}
}
cout << endl;
cout << "Deleting project" << endl;
cout << "What would you like to remove?" << endl;
int x = 1;
//storeid will display ids. How do I link them to `store` map?
for ( pt = projstore.begin(); pt != projstore.end(); ++pt ) {
cout << x << ". ";
pt->printprojname();
x++;
}
//Now to delete the selected project
int delP;
cout << "Enter number: ";
cin >> delP;
cin.ignore();
system("pause");
projstore.erase(projstore.begin()+delP-1);
// Students
cout << "\n Current students" << endl;
for(itr=mstore.begin(); itr!=mstore.end() ;++itr)
itr->second.printStudentInfo();
}
Look at how you add a Student to a Project:
void add (Student& student)
{
student.setProject (projname);
students.push_back (student); // <-- AHA!
}
First you assign the Project name to the Student, then the Project stores a copy of the Student. After that, the Project has no link to the original Student, and can't inform him/her of its own demise when the time comes.
You'll have to rethink this design; there are three major options: 1) the Students can look up their respective Projects in the store, 2) the Project can look up its Students in the students vector, or 3) the Project owns the Students (in which case they should probably be GraduateStudents).
EDIT:
If that's the way you want to do it, use map<int, Student> store to store the Students, using ID number as an index. Then a Project can have a vector<int> (or set<int>) of student ID numbers. It can look Students up in the store with ease.
EDIT:
To print out the entire collection of students:
for(map<int, Student>::const_iterator itr=store.begin(); itr!=store.end() ;++itr)
itr->second.print();
EDIT:
If the Project has a vector<int> of student ID numbers, then what argument do you think Project::add(?) should take?
EDIT:
The Project can act on a Student by means of the student ID number and access to mstore:
// in Project:
mstore[id].whatever()
EDIT:
Sometimes asking the right question -- or in this case, phrasing the question correctly -- is half the battle. 'Now how do I change "None" to the inserted project name?' A better way to put it is 'How does the Project change one of its Student's project from "None" to projname?' Once you put it that way, the answer is almost obvious:
// in Project:
mstore[id].setSProject(projname);
Note that Student does not yet have setSProject(string), you'll have to add it. Also, note that this solution is not ideal since 1) anybody can change a Student's project, and 2) a Student's project need not actually be the name of a real Project. There is more than one way to deal with these problems.