How to remove a struct element from a vector? - c++

I'm a newbie programmer and I'm working on a program that holds a registry of pets in a hotel (some silly exercise we saw in class, doesn't matter). I'm using vectors for holding the struct elements (pets). The code for the struct is this:
struct Pets{
string Name;
string Race;
string Owner;
int Tel;
}p;
And the function to ask for user input is this:
AddPet(vector<Pets> &vtnew)
{
Pets newpet;
cout << "Enter the pet's name: " << endl;
cin >> newpet.Name;
cout << "Enter the pet's race: " << endl;
cin >> newpet.Race;
cout << "Enter the owner's name: " << endl;
cin >> newpet.Owner;
cout << "Enter the owner's telephone number: " << endl;
cin >> newpet.Tel;
vtnew.push_back(newpet);
}
Ok, now I need to create a function to remove the pet by entering the name or something. Is there any way to do that?

A vector is an unsorted container so the simple solutions are really your only choice.
void RemovePet(std::vector<Pet> & pets, std::string name) {
pets.erase(
std::remove_if(pets.begin(), pets.end(), [&](Pet const & pet) {
return pet.Name == name;
}),
pets.end());
}
This is known as the Erase-remove idiom.
Note that this will remove all pets matching that name, not just one.

Related

Classes and OOP help C++

I'm having trouble with a simple code I have to for class, I'm trying to figure out how to add in a user input into a class, I've tried multiple things and could really use some assistance.
Code so Far:
#include <iostream>
#include <string>
using namespace std;
// Base class
class GameShow{
public:
string Name;
cout << "Enter name of constestant: ";
cin >> Name;
cout << "Welcome " << Name <<"! Let's get ready to play the FEUD!!" << endl;
};
// Derived class
class FamilyFued{
public:
points;
};
int main ()
{
GameShow TN;
TN.Name
return 0;
}
Classes are used to abstract the state and behavior of things.
State is in the form of class attributes.
The behaviour is in the form of class methods (functions).
This is a behaviour:
cout << "Enter name of constestant: ";
cin >> Name;
cout << "Welcome " << Name <<"! Let's get ready to play the FEUD!!" << endl;
So you need to put it inside a function:
class GameShow{
public:
string Name;
GameShow(){
cout << "Enter name of contestant: ";
cin >> Name;
cout << "Welcome " << Name <<"! Let's get ready to play the FEUD!!" << endl;
}
};
Based on what you have, you might want to wrap cout >> ...; cin <<...; part in a constructor:
class GameShow{
public:
string Name;
GameShow()
{
cout << "Enter name of constestant: ";
cin >> Name;
cout << "Welcome " << Name <<"! Let's get ready to play the FEUD!!" << endl;
}
};
Other than that, please refer to: The Definitive C++ Book Guide and List
You code missing too many basics, you need start with a good c++ book.
using namespace std; // is bad idea, mentioned in stack overflow thousands of times.
bad
class GameShow{
public:
string Name;
cout << "Enter name of constestant: ";
cin >> Name;
cout << "Welcome " << Name <<"! Let's get ready to play the FEUD!!" << endl;
};
Your cout and cin function should be used inside a constructor
class GameShow{
public:
string Name;
GameShow()
{
std::cout << "Enter name of constestant: ";
std::cin >> Name;
std::cout << "Welcome "
<< Name
<< "! Let's get ready to play the FEUD!!" << std::endl;
}
};
TN.Name // what this line doing in your main function ??
Assuming you wanted to print Name of GameShow class member, so change your line to below.
std::cout << TN.Name;

How to create a function to read/write data to struct members?

I'm trying to create a program that read and print students' data with c++. for that, I've created a struct Student, a function to read data from the user and assign it to a struct instance s1 and a function to print students' data on the screen, and I think the problem is with the function that read/write data.
Here is the my code:
#include<iostream>
#include<string>
using namespace std;
struct Student
{
char name[30];
int age;
double gpa;
string department;
};
Student read_data(Student x)
{
cout << "Name (30 characters maximum): ";
cin.get(x.name, 30);
cout << "Age: ";
cin >> x.age;
cout << "Department: ";
cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
return x;
}
void print_data(Student x)
{
cout <<
"\n***************************************************************" << endl;
cout << "Name: " << x.name << endl;
cout << "Age: " << x.age << endl;
cout << "Department: " << x.department << endl;
cout << "GPA: " << x.gpa << endl;
}
int main()
{
Student s1, s2, s3;
cout << "This program stores -Temporarily- data of three students\n" << endl;
cout << "Enter 1st student's data" << endl;
read_data(s1);
print_data(read_data(s1));
system("pause");
return 0;
}
The output of this code is:
This program stores data of three students
Enter 1st student's data
Name (30 characters maximum): Ahmed Maysara
Age: 22
Department: CS
GPA: 3.5
Name (30 characters maximum): Age: Department: GPA:
***************************************************************
Name:
Age: -858993460
Department:
GPA: -9.25596e+61
Press any key to continue . . .
As you see, the output is out of my expectations :) ..
Any help ?!
Both CinCout and David are correct.
There are a couple of problems with your code as it now stands.
The first problem is that while you successfully call the function read_data(s1), s1 is a just a copy. So, when the function sets all of the values for the student using cin, it is really just setting a copy's values. You can either make it so that you are passing in the original, or you can return the student (which you are doing) and set s1 equal to the result (which you are not).
To make sure that you pass in the original, you can go to where you declared read_data. Instead of saying Student read_data(Student x), you should place an ampersand after the parameter that you don't want to copy Student read_data(Student &x). This is called passing by reference (you reference the original instead of referencing by copy)
Alternatively, you could con just set s1 to the result where you call it in main. You could say s1 = read_data(s1); and that would work fine, though a bit more inefficiently.
Lastly, the other glaring error in the code is that you accidentally call read_data again when you say print_data(read_data(s1)). Instead, say print_data(s1).
Instead of passing and returning the structure object each time on call of read_data and print_data we could add those inside the structure itself, We could create object of Student and call the functions read and print within the same.
struct Student
{
char name[30];
int age;
double gpa;
string department;
Student(): age(0), gpa(0)
{
memset( name, 0, 30 );
}
void read()
{
cout << "\nName (30 characters maximum): ";
cin.get(name, 30);
cout << "\nAge: ";
cin >> age;
cout << "\nDepartment: ";
cin >> department;
cout << "\nGPA: ";
cin >> gpa;
}
void print()
{
cout << "\n***************************************************************" << endl;
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Department: " << department << endl;
cout << "GPA: " << gpa << endl;
}
};
int main()
{
Student s1;
s1.read();
s1.print();
return 0;
}
You are passing copy of s1 into the read_data function, but not bothering to update the value based on the return arg. i.e. something like this should work.
s1 = read_data(s1);
print_data(s1);
Alternatively, pass by reference instead of value:
void read_data(Student& x)
{
cout << "Name (29 characters maximum): "; // requires null terminator
cin >> x.name; // just read into the buffer directly
cout << "Age: ";
cin >> x.age;
cout << "Department: ";
cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
}
And then later:
read_data(s1);
print_data(s1);
change you read_data with something like this
void read_data(Student& x)
{
cout << "Name (30 characters maximum): ";
///cin.get(x.name, 30);
cin.getline(x.name, 30);
cout << "Age: ";
cin >> x.age;
cin.ignore();
cout << "Department: ";
std::getline(cin, x.department);
///cin >> x.department;
cout << "GPA: ";
cin >> x.gpa;
cin.ignore();
// return x; can't return a value from a void function
}
and in main function or where you are calling the read_data function use
Student s1, s2, s3;
cout << "This program stores -Temporarily- data of three students\n" << endl;
cout << "Enter 1st student's data" << endl;
read_data(s1);
read_data(s2);
read_data(s3);
the reason you are getting weird values in return is that you capture buffer with cin >> instead getline
see
description of getline function
description of cin.ignore function

Create an array that holds struct objects C++

I am a novice programmer and I am creating a program that holds several objects of a struct type. The program needs to accept user input but I don't know how to do it. First, here's the code I'm using to define the struct:
struct Apartment{
int number;
string owner;
string condition;
}ap;
And here's the code I'm using to ask for user input:
cout << "Enter the apartment number: " << endl;
cin >> ap.number;
cout << "Enter the name of the owner: " << endl;
cin >> ap.owner;
cout << "Enter the condition: " << endl;
cin >> ap.condition;
apartment building[50] = { ap.number, ap.owner, ap.condition};
The last line of code is how I am trying to save the object in an array, bu I don't know if it works.
I later need to print all the objects, so it would be nice if you helped me with that too. I am using Visual Studio 2013 as a compiler, in case it makes any difference.
First of all, let's understand what you are doing.
struct Apartment{
int number;
string owner;
string condition;
}ap;
Firstly, you create an Apartement struct which have the name "ap".
cout << "Enter the apartment number: " << endl;
cin >> ap.number;
cout << "Enter the name of the owner: " << endl;
cin >> ap.owner;
cout << "Enter the condition: " << endl;
cin >> ap.condition;
Secondly, (I assume that you are in your main function) you are asking the user to enter some information. You have to keep in mind that cin only that the first word and stop at the first whitespace it sees if you plan to save more word, you should use getline. See this link for more information : http://www.cplusplus.com/doc/tutorial/basic_io/
apartment building[50] = { ap.number, ap.owner, ap.condition};
Finally, your last line will crash for two reasons. Firstly, because the type apartment does not exist. I believe you meant to write Apartment. Secondly because you cannot create an array like this. I suggest you to look at this: http://www.cplusplus.com/doc/tutorial/arrays/
I am not sure exactly what you want to do, so I will give you a sample of code that ask a user how many apartment he has and ask the information for the number of apartment he owns.
struct Apartment{
int number;
string owner;
string condition;
};
int main() {
cout << "Hello, how many apartment do you own?";
int nbAppt = 0;
cin >> nbAppt;
Apartment appt[nbAppt];
for(int i = 0; i < nbAppt; i++) {
cout << "Appartment number " << i << endl;
cout << "Enter the apartment number: ";
cin >> appt[i].number;
cout << "Enter the name of the owner: ";
cin >> appt[i].owner;
cout << "Enter the condition: " << endl;
cin >> appt[i].condition;
}
}
Ps: Please note that I assumed that you included namespace std;
Ps2: I did not include any relevant include.
struct Apartment{
int number;
string owner;
string condition;
}ap;
void AddApartment(vector<Apartment> &vtnew)
{
Apartment building;
cout << "Enter the apartment number: " << endl;
cin >> building.number;
cout << "Enter the name of the owner: " << endl;
cin >> building.owner;
cout << "Enter the condition: " << endl;
cin >> building.condition;
vtnew.push_back(building);
}
void DisplayApt(vector<Apartment> vtnew)
{
vector<Apartment> ::iterator it;
for (it = vtnew.begin(); it != vtnew.end(); it++)
{
cout << "apartment number" <<it->number;
cout << "name of the owner" << it->owner;
cout << "condition" << it->condition;
}
}
int main()
{
vector<Apartment> vt;
AddApartment(vt);
AddApartment(vt);
AddApartment(vt);
DisplayApt(vt);
return 0;
}
What you are doing in your code is to declare an array for apartment to hold 50 apartments, but when you are using vectors we need not to give the count beforehand, we can keep adding the apartments, without worrying about the size!
I think you have a confuse here.
Apartment building[50]
means that this is an array of 50 elements and each element is a struct with type Apartment.
For example, it should be like this:
struct Apartment obj1;
struct Apartment obj2;
struct Apartment obj3;
Apartment building[3] = {obj1, obj2, obj3};
And I wonder what is the main purpose of "save object in an array" ?
Every element of an array should have same datatype and every field of a struct may not have same datatype, so that you shouldn't "save object in an array".

Create a vector of base class objects and store derived class objects within

I am trying to create an employee database (Vector of Employees). There are 3 types of employees ie. employees is the base class and Manager, Engg and Scientist are derived class.
Every employee has first name and last name. In addition to the name, each of the 3 types of employees have unique stats ie. Manager has number of meetings/week whereas the Engg has work experience and so on.
I have a couple of questions
1. Should I upcast the derived objects to the base class or downcast the base class to the derived class?
2. How do I use polymorphism to override methods, since I want the user to add an employee type and based on the type selected the respective entry fields should appear ie. in case of a Manager, in addition to the first and last names, the program should also ask for meetings/week?
Here is my Class file
class Employee{
public:
Employee();
Employee(string fName, string lName, int sal);
virtual void printEmp();
string getFirstName();
string getLastName();
protected:
string m_fName;
string m_lName;
int m_sal;
};
class Manager : public Employee{
public:
Manager();
Manager(string fName, string lName, int sal, int meets, int hols);
void printEmp();
protected:
int m_meets;
int m_hols;
};
Here is the implementation
Employee::Employee(){
m_fName = "Default";
m_lName = "Default";
m_sal = 0;
}
Employee::Employee(string fName, string lName, int sal){
m_fName = fName;
m_lName = lName;
m_sal = sal;
}
void Employee::printEmp(){
cout << "First Name: " << m_fName << endl
<< "Last Name: " << m_lName << endl
<< "Salary: " << m_sal << endl;
}
string Employee::getLastName(){
return m_lName;
}
string Employee::getFirstName(){
return m_fName;
}
Manager::Manager(string fName, string lName, int sal, int meets, int hols) : Employee(fName, lName, sal), m_meets(meets), m_hols(hols)
{
//empty
}
void Manager::printEmp(){
Employee::printEmp();
cout << "Meets/Week: " << m_meets << endl
<< "Holidays/Year: " << m_hols << endl << endl;
Here is the main
int main(){
bool exit = false;
vector<Employee*> dBVector;
while (!exit){
cout << "Welcome to Employee Database, Enter an option to continue..." << endl;
cout << "1) Add an Employee, 2) Delete an Employee, 3) Save Database, 4) Exit" << endl;
int input;
cin >> input;
string fNameInp;
string lNameInp;
int salInp;
string lNameSearch;
int i; // for loop in Delete employee case
bool deleted = false;
switch (input){
case 1: //Add
cout << "1) Add a Manager, 2) Add an Engg, 3) Add a Researcher" << endl;
int empInput;
cin >> empInput;
if (empInput == 1){
cout << "Enter First Name: ";
cin >> fNameInp;
cout << "Enter Last Name: ";
cin >> lNameInp;
cout << "Enter Salary: ";
cin >> salInp;
cout << "Number of meetings/week: ";
int meetsInp;
cin >> meetsInp;
cout << "Number of holidays/year: ";
int holsInp;
cin >> holsInp;
Manager mEmp(fNameInp, lNameInp, salInp, meetsInp, holsInp);
Employee &emp = mEmp;
dBVector.push_back(&mEmp);
dBVector[dBVector.size()-1]->printEmp();
}
else if (empInput == 2){
cout << "Enter First Name: ";
cin >> fNameInp;
cout << "Enter Last Name: ";
cin >> lNameInp;
cout << "Enter Salary: ";
cin >> salInp;
cout << "Cpp Experience (Y/N): ";
string cppInp;
cin >> cppInp;
cout << "Years of experience: ";
float expInp;
cin >> expInp;
cout << "Engg Type (Chem, Mech, IT): ";
string typInp;
cin >> typInp;
Engg eEmp(fNameInp, lNameInp, salInp, cppInp, expInp, typInp);
Employee &emp = eEmp;
dBVector.push_back(&eEmp);
dBVector[dBVector.size() - 1]->printEmp();
}
else if (empInput == 3){
cout << "Enter First Name: ";
cin >> fNameInp;
cout << "Enter Last Name: ";
cin >> lNameInp;
cout << "Enter Salary: ";
cin >> salInp;
cout << "School of PhD: ";
string schoolInp;
cin >> schoolInp;
cout << "Topic of PhD: ";
string topImp;
cin >> topImp;
Researcher rEmp(fNameInp, lNameInp, salInp, schoolInp, topImp);
Employee &emp = rEmp;
dBVector.push_back(&rEmp);
dBVector[dBVector.size() - 1]->printEmp();
}
break;
case 2: // Delete Emp
for (int x = 0; x < dBVector.size(); x++){
dBVector[x]->getLastName();
cout << endl;
}
cout << "Input Last name of the employee to delete: " << endl;
cin >> lNameSearch;
for (i = 0; i < dBVector.size(); i++){
if (dBVector[i]->getLastName() == lNameSearch){
dBVector.erase(dBVector.begin() + i);
cout << dBVector[i]->getFirstName() << "has been deleted from database";
deleted = true;
break;
}
}
if (deleted == false && i == dBVector.size()){
cout << "No Employee with Last Name - " << lNameSearch << " exists in Database." << endl;
}
else
break;
case 3: //save
cout << "saving..." << endl;
break;
case 4: //exit
exit = true;
break;
}
}
}
Please Help!
Firstly, if you want to use polymorphism you need to store pointers in your vector. As the vector is the sole owner of the employees something like std::vector<std::unique_ptr<Employee>> would be suitable.
Edit: I see you have updated the vector to use pointers. But you are storing a pointer to a local stack allocated object, e.g mEmp. This will not work, when the mEmp variable goes out-of-scope at the closing brace the object will be deleted and you will be left with a dangling pointer in your vector that points to a deleted object. Using this dangling pointer is undefined behaviour. You need to allocate the Manager on the heap using new. Then the object will not be deleted when the variable goes out-of-scope but you do need to remember to delete the object when you are done. Something like unique_ptr makes this easy.
Regarding your questions:
Try to minimize explicit casting, especially downcasting. At the point that you store the Employee in the vector it will be implicitly upcast from the derived class to Employee but other than that there is not much need for casting.
You have roughly the right idea when it comes to overriding methods, if you call the virtual printEmp method on an Employee pointer it will call the override in the derived class.
If you are happy for the user input to be the responsibility of the Employee classes you could simply add a virtual method that initializes the employee using suitable input from the user. But I would be tempted to keep that separate from your domain objects. You need a switch statement on the user choice of employee type anyway so polymorphism doesn't gain you much there.
If you really want to use polymorphism for the employee creation I would suggest using something like the Abstract Factory pattern.
Here is my suggestion anyway:
#include <vector>
#include <string>
#include <iostream>
#include <memory>
class Employee {
public:
Employee(std::string fName, std::string lName, int sal);
virtual ~Employee();
virtual void printEmp();
protected:
std::string m_fName;
std::string m_lName;
int m_sal;
};
class Manager : public Employee {
public:
Manager(std::string fName, std::string lName, int sal, int meets, int hols);
void printEmp() override;
protected:
int m_meets;
int m_hols;
};
Employee::Employee(std::string fName, std::string lName, int sal)
: m_fName(fName), m_lName(lName), m_sal(sal) {
}
Employee::~Employee() {
}
void Employee::printEmp(){
std::cout << "First Name: " << m_fName << "\n"
<< "Last Name: " << m_lName << "\n"
<< "Salary: " << m_sal << "\n";
}
Manager::Manager(std::string fName, std::string lName, int sal, int meets, int hols)
: Employee(fName, lName, sal), m_meets(meets), m_hols(hols){
}
void Manager::printEmp(){
Employee::printEmp();
std::cout << "Meets/Week: " << m_meets << "\n"
<< "Holidays/Year: " << m_hols << "\n";
}
std::unique_ptr<Manager> createManager() {
std::cout << "Enter First Name: ";
std::string fNameInp;
std::cin >> fNameInp;
std::cout << "Enter Last Name: ";
std::string lNameInp;
std::cin >> lNameInp;
std::cout << "Enter Salary: ";
int salInp;
std::cin >> salInp;
std::cout << "Number of meetings/week: ";
int meetsInp;
std::cin >> meetsInp;
std::cout << "Number of holidays/year: ";
int holsInp;
std::cin >> holsInp;
std::cout << "\n";
return std::make_unique<Manager>(fNameInp, lNameInp, salInp, meetsInp, holsInp);
}
std::unique_ptr<Employee> createEmployee() {
int input;
std::cout << "1) Add a Manager, 2) Add an Engg, 3) Add a Researcher\n";
std::cin >> input;
switch (input){
case 1:
return createManager();
default:
return nullptr;
}
}
int main() {
std::vector<std::unique_ptr<Employee>> dBVector;
std::cout << "Welcome to Employee Database, Enter an option to continue...\n";
std::cout << "1) Add an Employee"
<< ", 2) Delete an Employee"
<< ", 3) Save Database"
<< ", 4) Exit\n";
int input;
std::cin >> input;
switch (input){
case 1:
dBVector.push_back(createEmployee());
break;
default:
break; // Do nothing
}
dBVector.at(0)->printEmp();
}
Live demo
You may want to store pointers in the vector to avoid slicing, as others mentioned. Then each employee could have their own input method and ask the right questions to initialize themselves (main would not implement that but only call the respective employee's virtual input function). Input and output are conceptually sysmmetrical operations which hints at implementing them symmetrically, i.e. in this case both as member functions.

My list objects are being destroyed

list<Book> *books = new list<Book>;
list<Book>::iterator pos;
void Administrator::addBook()
{
Book *newBook = new Book();
cout << "Would you like to enter a book?" << endl;
cin >> userInput;
cout << endl;
if (userInput == "yes")
{
cout << "What is the title of the book you want to enter?" << endl;
cin >> title;
cout << "What is the author of the book you want to enter?" << endl;
cin >> author;
cout << "What is the ISBN of the book you want to enter?" << endl;
cin >> ISBN;
cout << endl;
newBook->setTitle(title);
newBook->setAuthor(author);
newBook->setISBN(ISBN);
newBook->setAvailability(true);
books->push_back(*newBook);
}
}
*****************
I really need help with this, i have received a few answers today but none have helped me with this problem. This is my admin class. It creates books on the heap and stores them in an stl::list
void Guest::searchBook(Book* search)
{
string searchBook;
cout << "What book would you like to search for?" << endl;
cin >> searchBook;
printBookDetails();
}
This is my Guest class, what i would like to do here is to search through the list of books i created in my Administrator class but when it goes into the function printBookDetails, my list contains no elements, im assuming they've been destroyed.
Administrator* admin1 = new Administrator("jayfitz91", 24681357);
Guest* guest1 = new Guest("guest", 0000);
void main()
{
//Everything here works fine
admin1->addBook();
admin1->addBook();
admin1->makeAvailable();
admin1->printBookDetails();
//My list is destroyed at this point and it returns nothing
guest1->printBookDetails();
My Guest class inherits the printBookDetails from my Administrator class
All of the admin functions work but as soon as it gets to guest, the elements disappear.
Is there anyway i can get around this? The help would greatly be appreciated
Thanks to #OldProgrammer, i realised i had to return the list of books from my Admin class and pass it through as a parameter to my printBookDetails method in my guest class:
//Admin class
//Now returning a list
list<Book> Administrator::addBook()
{
Book *newBook = new Book();
cout << "Would you like to enter a book?" << endl;
cin >> userInput;
cout << endl;
if (userInput == "yes")
{
cout << "What is the title of the book you want to enter?" << endl;
cin >> title;
cout << "What is the author of the book you want to enter?" << endl;
cin >> author;
cout << "What is the ISBN of the book you want to enter?" << endl;
cin >> ISBN;
cout << endl;
newBook->setTitle(title);
newBook->setAuthor(author);
newBook->setISBN(ISBN);
newBook->setAvailability(true);
books->push_back(*newBook);
}
return *books;
}
//Guest class function
void Guest::printBookList(list<Book> *tempList)
{
pos = tempList->begin();
for (pos = tempList->begin(); pos != tempList->end(); ++pos)
{
cout << pos->getTitle() << "\n"
<< pos->getAuthor() << "\n"
<< pos->getISBN() << "\n"
<< pos->getAvailability() << "\n"
<< "******************************" << endl;
}
}
//Main class function
//Create a temporary variable for the list
list<Book> tempList;
//pass it through to the method
guest1->printBookList(&tempList);
First off, you don't have to dynamically create your list object.
list<Book> books = new list<Book>();
You do this because
you have less responsibility: you don't have to release the resources contained by books. It will automatically be released.
list is a stl container, which means it automatically handles dynamic allocations.
This is different if you use an dynamically allocated array...
I think your list is "gone" is because Guest and Administrator has two entirely different list.
To solve this issue, you should grant access to the book list that Administrator has to your Guest.
Or extract out the book list and store it in another class that allow access to the list to both Administrator and Guest.