Sorting, adding, removing, and printing objects in C++ - c++

I initialized objects in my code using a house number (int) and the person's name (string). This part of my code works and it displays the house number and person correctly.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//AddressBook class definition
class AddressBook
{
public:
//Declare a constructor that has one parameter for each data member
AddressBook(int, string);
//Declare a set method for house number
void setHouseNum(int);
//Declare a get method for house number
int getHouseNum();
//Declare a set method for name
void setName(string);
//Declare a get method for name
string getName();
void displayAddressBook();
private:
//Declare a int data member for house number
int houseNum;
//Declare a string data member for name
string name;
};
// constructor
AddressBook::AddressBook(int num, string personName)
{
setHouseNum(num);
setName(personName);
}
void AddressBook::setHouseNum(int num)
{
houseNum = num;
}
int AddressBook::getHouseNum()
{
return houseNum;
}
void AddressBook::setName(string personName)
{
name = personName;
}
string AddressBook::getName()
{
return name;
}
void AddressBook::displayAddressBook()
{
cout << getHouseNum() << " " << getName() << endl;
}
int main()
{
AddressBook addressBook(3, "Jim");
addressBook.displayAddressBook();
AddressBook addressBook2(5, "Bob");
addressBook2.displayAddressBook();
AddressBook addressBook3(2, "Jeb");
addressBook3.displayAddressBook();
string command;
cout << "Available Commands Are:" << endl;
cout << "Add, Remove, Sort, Print" << endl;
return 0;
}
Output:
3 Jim
5 Bob
2 Jeb
Available Commands Are:
Add, Remove, Sort, Print
The next part is what I'm having trouble with. I'm supposed to read the user input to see what they want to do and perform the operations listed above. So, if they say Add, and then enter "2 Jeb", the code has to say 2 already exists. If it doesn't exist, it has to add it as an object and print the entire list back out.
I know that you can use getline(cin,name) to get the name from the user but I do not know how to implement that in my code to do what I want it to. Once I get the user input string, how do I create an object with it? Also, how do you read an integer the user inputs into an object because I read that getline works for strings and not integers.
Once I read the integer and string input from the user, how do I check if the house number already exists in my objects? If I can get some help with just these two things I can figure the rest out.
Thank you.

Related

Passing array off as reference in c++ without using pointer

I have a quick question regarding an assignment I have to complete for C++. The teacher has required that I include the functions below:
void getPlayerInfo(Player &);
void showInfo(Player);
int getTotalPoints(Player [], int);
But I'm having trouble working on the first function....I'm not sure if I'm calling the array of structures properly. Can someone look it over and see what I'm doing wrong? I fiddled with it a bit and I'm able to call the array and pass off a pointer to the array but the teacher requested the "&" symbol be there so there must be another method I'm unaware of. Please help! Thanks
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
// Structure to hold information about a player
struct Player
{
string name; // to hold the players name
int number; // to hold players number
int points; // to hold the points scored by the player
};
// Function prototypes
void getPlayerInfo(Player &); // function to get the players information from the user
void showInfo(Player); // function to show the table
int main()
{
const int numPlayers = 12; // Constant to hold the number of players
Player team[numPlayers]; // array to hold 12 structures
// Gather information about all 12 players
getPlayerInfo(team);
showInfo(team);
return 0;
}
// Function to get the players info
void getPlayerInfo(Player& team)
{
for (int count = 0; count < 12; count++)
{
cout << "PLAYER #" << (count + 1) << endl;
cout << "----------" << endl;
cout << "Player name: ";
cin.ignore();
getline(cin, team[count].name);
cout << "Player's number: ";
cin >> team[count].number;
cout << "Points scored: ";
cin >> team[count].points;
cout << endl;
}
}
getPlayerInfo() does not accept an array, it accepts a reference to a single Player object.
You need to call getPlayerInfo() for each player in your array. Move your loop outside of getPlayerInfo() and into main().
You've misunderstood the intent of these functions.
Guessing from the information you've provided, getPlayerInfo is intended to get the information of an individual player, and showPlayerInfo is intended to show the information of an individual player.
You're trying to use these functions to do something they aren't intended to do, so it's a good thing that you are having trouble figuring out how to call and how to implement them.
Consider this experience as a object lesson in requirement gathering.

Writing an object with a pointer to another object to an ASCII file (C++)

I'm making a program that keeps track of different employees. Some of the employees have partners (wifes and husbands), so all of the Employee objects have a data member called "Partner* partner" (a pointer to a Partner object).
My problem comes when I want to write an Employee to a file. I can successfully write all of the Employee data (name, address, birth date etc.) to the file, but I don't know how to write the partner to file. I have a function in the Partner class called "writeToFile" which outputs all of the partner data, but I don't know how to "connect" it to the correct Employee object. I tried to just output the "partner"-object to the end of the file, but that just added a bunch of zeros.
Should I use two separate files (one for employees and one for partners), or should I just append the partner data to the employee data? Wouldn't that mess up the file structure when reading it back in, since only some of the employees have partners and some of the partner objects just point to NULL?
My classes inherits each other, so both the Partner and Employee class inherits the Adult class, which again inherits the Person class.
Can anyone give me a "pointer" to what is the best way of writing an object which has a pointer to another object inside it? Here's my temporary code btw, if it is of any interest:
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
#include <cstdlib>
using namespace std;
const int MAXTXT = 80;
class Person {
protected:
char* firstname;
char birthdate[6];
public:
Person() {
char fname[MAXTXT];
cout << "First name: "; cin.getline(fname, MAXTXT);
firstname = new char[strlen(fname + 1)];
strcpy(firstname, fname);
cout << "Birth date (DDMMYY): ";
cin >> birthdate; cin.ignore();
}
void display() {
cout << "\nFirst name: " << firstname;
cout << "\nBorn: " << birthdate;
}
void writeToFile(ofstream & ut) {
ut << firstname << "\n" << birthdate;
}
};
class Adult: public Person {
protected:
char* lastname;
public:
Adult() {
char lname[MAXTXT];
cout << "Last name: "; cin.getline(lname, MAXTXT);
lastname = new char[strlen(lname + 1)];
strcpy(lastname, lname);
}
void writeToFile(ofstream & out) {
out << "\n" << lastname << "\n";
}
void display() {
cout << "\nLast name: " << lastname;
}
};
class Partner: public Adult {
private:
int phone1;
int phone2;
public:
Partner() {
cout << "Phone (mobile): "; cin >> phone1;
cout << "\nPhone (job): "; cin >> phone2; cin.ignore();
}
void writeToFile(ofstream & out) {
Person::writeToFile(out);
Adult::writeToFile(out);
out << "\n" << phone1 << " " << phone2;
}
void display() {
Person::display();
Adult::display();
cout << "\nPhone (mobile): " << phone1;
cout << "\nPhone (job): " << phone2;
}
};
class Employee: public Adult {
private:
int nr;
char* address;
Partner* partner;
public:
Employee() {
}
Employee(int n) {
char adr[MAXTXT];
nr = n;
cout << "Address: "; cin.getline(adr, MAXTXT);
address = new char[strlen(adr + 1)];
strcpy(address, adr);
partner = NULL;
}
void changePartner() {
Partner::Partner();
}
void writeToFile(ofstream & out) {
Person::writeToFile(out);
Adult::writeToFile(out);
out << nr << "\n" << address << endl;
}
void display() {
Person::display();
Adult::display();
cout << "\nAddress: " << address;
if(partner) {
partner->display();
}
}
int returnEmpNr() {
return nr;
}
};
Employee* employees[100];
int lastUsed = 0;
int main() {
}
void writeToFile() {
ofstream outfile("EMPLOYEES.DAT");
ofstream outfile2("PARTNERS.DAT");
outfile << lastUsed << "\n";
for(int i = 1; i <= lastUsed; i++) {
employees[i]->writeToFile(outfile);
}
A pointer is meaningless except to a single run of a program and could very well be meaningless by the time the file is read if the pointer at value has gone out of scope. The odds of the same Partner being in the same spot in memory, assuming space has even been allocated for it, the next time around could be as bad as 1 in 18,446,744,073,709,551,616 and being wrong has often fatal results. And those fatal results mean you got lucky. You could smash perfectly valid memory that belongs to something else, and results in behaviour that is weird, undefined, and much harder to debug than an outright crash.
In C++ pointers are often a sucker bet. Use them as a last resort because they can really ramp up the amount of code you need to write.
I recommend two lists (but not necessarily two files. Both lists can easily exist in one file) one of Partners and one of Employees. The Partners don't seem to need to know about the Employees, so save yourself some trouble and write out and read in the partner list first.
When writing the Employee list, don't store the Partner pointer because it won't work. Instead store the index of the Partner in the Partner list. Then when you read the Employee list, you can read the Partner's position in the Partner table look up that Partner, and point to them. This is why it's much easier to write and read the Partners first; it is hard to look up data in a list that hasn't been read yet.
Or ditch the concept of Partner pointers entirely and always use the index to look the Partner up. This is much safer approach, so long as you always append new partners to the list and never insert into the list or do something silly like shuffle the list.
While we're messing with pointers, take a good solid read of "What is The Rule of Three?" because you are heading into a quagmire of memory management carnage.
As written every time you copy an Employee, you will get another Employee that is copied stupidly. It copies the pointers, not the content, so you now have 2 Employee objects pointing to the same names and Partners. When you free the memory allocated to the partner and names, which you don't and really, really should, the other copy is pointing at memory that your program no longer owns and becomes a ticking time bomb just waiting to crash your program.
Using a std::vector<Partner> (note it is a vector of Partner, not Partner *. This allows the vector to own and manage all of the memory for you and not just the memory needed by the list) and indexes clears up the problem with Partners, because the std::vector manages the memory for you, but the names are still waiting to kill the program. Replacing the char *s with std::string will solve that problem, also by moving the memory management burden from your code to std::string where it was written for you some time in the 1990s and has been under use in millions of programs ever since. Not many bugs left to trip over after 20 years.
If you have to use pointers and arrays of pointers, you need to make custom destructors, copy constructors, move constructors, assignment operators and move operators. That's a lot of extra work.
But those vectors and strings contain pointers and you have to handle writing them carefully. This topic, serialization, has been beaten to death elsewhere, so here's a link to a reputable site that can probably handle it better than I can.

Properly Store Object in Vector

I'm brand new to C++, and this is my first time posting (recipe for disaster). I've spent about a day trying to resolve my problem/question, in the mean time finding no easily recognizable solution on the forums. It's possible that my question has already been asked or that a solution has already been posted but I've overlooked it or misunderstood it. A similar post exists here, but it's not obvious to me what to do with the information.
I'll provide a concise, high-level summary of the point of this code. I'll then ask the specific question(s) to which I'm unable to find an answer, and I'll follow with the code I've written.
SUMMARY: I'm creating a program to help do bookkeeping for a game. The game may have any number of players, and each player having a small list of attributes/members (e.g. playerName, playerAllegiance, etc.) which are elements of a Player class/object. The user is first asked to input the name of each player (enteredName), and the program must create a new Player object for each name that's entered. This seems to be appropriately handled by a dynamic array, so I chose to use a vector (called playerIndex) to store each Player object. A for-loop allows the user to input names, each name instantiating a new Player object which is to be stored (copied?) into playerIndex using vector::push_back. At the conclusion of the for-loop, the user should be left with a vector of Player objects, each Player object storing a name in its playerName member.
QUESTION/PROBLEM: The code seems to work proprly when monitoring the vector inside the aforementioned for-loop. Immediately after the user enters the Nth player's name, the program spits out the playerName string stored in the Nth element of playerIndex using a Player class function getPlayerName() [actual code: playerIndex[playerCounter].getPlayerName()]. As soon as the user enters a blank playerName (i.e. presses enter without entering a name), it indicates the user has entered all player names, so the for-loop terminates. Just after this loop, a loop which is designed to output the playerName of each Player object stored in playerIndex does not output the expected names. I don't know why this is happening, but based on my very minimal knowledge of constructors, I'm guessing it has something to do with a copy or move constructor for the Player class. Can anyone clearly explain how to handle this issue? I fear I may be making a pitifully stupid, novice mistake and/or misunderstanding a key concept of C++.
CODE: This code is cropped/simplified to be as clear as possible. For example, the Player class is shown to have only one member (playerName) while, in the original code, it has four or five other members.
//HeaderPlayerClass.hpp
#include <iostream>
#include <string>
#ifndef PLAYERCLASS_HPP
#define PLAYERCLASS_HPP
using std::string;
class Player {
private:
string *playerName;
public:
Player();
Player(string);
~Player();
string getPlayerName();
};
#endif
//PlayerClass.cpp
#include "HeaderPlayerClass.hpp"
#include <iostream>
#include <string>
using std::string;
Player::Player() {
playerName = new string;
}
Player::Player(string enteredName) {
playerName = new string;
*playerName = enteredName;
}
Player::~Player() {
delete playerName;
}
string Player::getPlayerName() {
return *playerName;
}
//main.cpp
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include "HeaderPlayerClass.hpp"
using std::cin;
using std::cout;
using std::string;
using std::vector;
int main(int argc, char** argv) {
string buffer;
vector<Player> playerIndex;
int playerCounter = 0;
for(;;) {
if(playerCounter==0) {
cout << "\nEnter player name and press enter; leave blank and press enter to continue.\n";
}
cout << "\nPlayer " << playerCounter+1 << ":";
getline(cin, buffer);
if(buffer == "esc") {
cout << "PROGRAM EXITED BY USER\n";
return 0;
}
if(buffer.empty()) {
break;
}
playerIndex.push_back(Player(buffer));
cout << "Player " << playerCounter+1 << "'s name:" << playerIndex[playerCounter].getPlayerName() << "\n";
++playerCounter;
}
for(int ii = 0 ; ii < playerIndex.size() ; ii++) {
cout << "\nThis should display player " << ii+1 << "'s name:" << playerIndex[ii].getPlayerName();
}
return 0;
}
class Player {
private:
string *playerName;
Do not store a pointer to the string, store the string itself
class Player {
private:
string playerName;
Constructor
Player::Player() {
playerName = new string;
}
This is unnecessary if you store the string itself - the default constructor will initialize it for you.
Here is where the problems start - this will leave you vulnerable to memory leaks unless you carefully write a destructor
Player::Player(string enteredName) {
playerName = new string;
*playerName = enteredName;
}
All you need, if you store the string itself:
Player::Player( const string& enteredName)
: playerName ( enteredName )
{}
You constructor is really scary. Just leave things to the default destructor when you store the string itself
Player::~Player() {
delete playerName;
}
Next, you are working too hard keeping your own counter. std::vector maintains its own count and using
playerIndex.size()
will save trouble and bugs

Creating an employee class

I am attempting to write the following:
1) Write the class definition for a class named Employee with name and salary as employee objects. The class contains two member functions: the constructor and a function that allows a program to assign values to the data members.
2) Add two member functions to the Employee class. One member function should allow any program using an employee object to view the contents of the salary data member. The other member function should allow the program to view the contents of the employee name data member.
3) Add another member function to the Employeeclass. The member function should calculate an employee objects new salary, based on a raise percentage provided by the program using the object. Before calculating the raise, the member function should verify that the raise percentage is greater than or equal to zero. If the raise percentage is less than zero, the member function should display an error message.
4) Write a main function that will create an array of employee objects, assign
values to the objects, display the names and current salaries for all objects,
ask user for the raise percentage and then calculate and display new salaries
for all objects.
I have attempted this with the following code:
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
class EMPLOYEE
{
public:
EMPLOYEE();//
EMPLOYEE(string name, int salary);//
public:
string name;//name to be input
int salary;//salary to be input
public:
int enter_values();
int output_values();
int NEW_SALARY( int percentage_raise);
};
//default constructor
EMPLOYEE::EMPLOYEE()
{
name = "";
salary = 0;
}
//constructor with name/salary variables
EMPLOYEE::EMPLOYEE(string NAME, int SALARY)
{
name= NAME;
salary= SALARY;
}
//name and salary to be input...
int EMPLOYEE::enter_values()
{ cout<<"Enter name and salary: ";
cin>> name;
cin>>salary;
}
//output
int EMPLOYEE::output_values()
{ cout<<"Name: "<<name<<endl;
cout<<"Salary: "<<salary<<endl;
}
//
int EMPLOYEE::NEW_SALARY(int percentage_raise)
{
EMPLOYEE updated_salary;
if ( percentage_raise >= 0){salary= salary *(percentage_raise/100);
}
else if(percentage_raise< 0)
{ cout<<"Error Message"<<endl;
}
return percentage_raise;
}
int main()
{
EMPLOYEE employees[100];
EMPLOYEE.NEW_SALARY();
int percent= 0;
int i;
for(i =0 ;i<100 ; i++)
{ employees[i]=EMPLOYEE();
employees[i].enter_values();
employees[i].name;
employees[i].salary;
employees[i].output_values();
cout<<"How much should the salary be raised by?"<<endl;
cin>>percent;
cout<<EMPLOYEE.name<<"'s new salary is "<<percentage_raise<<endl;
}
}
However, I cannot access the parts I need to store the information into the array in the main function, nor can I apply the percentage raise when the program prompts the user.
I'm pretty sure I have syntax errors which I am unaware of. I'm not asking for someone to do everything for me, but I would appreciate a steer in the right direction. I don't quite understand classes and how to call them into different parts of a program. Thank you for your time.
You have almost everything in good order.
Things to fix:
The line
if ( percentage_raise >= 0){salary= salary *(percentage_raise/100);
will set salary to zero unless percentage_raise is greater than 100. That's because the expression (percentage_raise/100) will be an integer division and will evaluate to zero, unless pecentage_raise is greater than 100.
You can fix it with:
if ( percentage_raise >= 0)
{
int raise = (salary*percentage_raise)/100;
salary += raise;
}
The line
EMPLOYEE.NEW_SALARY();
is going to produce a compiler error since there is no object named EMPLOYEE.
You can safely remove that line. It's not serving any purpose.
You are missing a call to set the percentage raise after you read the input. You need the line
employees[i].NEW_SALARY(percent);
immediately after you read percent.
The following line is incorrect.
cout<<EMPLOYEE.name<<"'s new salary is "<<percentage_raise<<endl;
since there is no object named EMPLOYEE. You can replace it with:
cout<<employees[i].name<<"'s new salary is "<<employees[i].salary<<endl;
class Employee
{
public:
Employee();
int salary;
};
Employee::Employee() { salary = 10; }
int main()
{
Employee joe;
std::cout << "Joe Salary: " << joe.salary << std::endl;
joe.salary = 15;
std::cout << "Joe New Salary: " << joe.salary << std::endl;
}
Usually, you will want your data members to be private and use an accessor method to provide the values of the data members which, again, should be private.

C++, error no match for operator<<

Please guide me with this.I have to write a program containing a class called VectorCollection that will be used to store a collection of vectors whose instances are of type string. I get the following error
no match for operator<< in std::cout
when i try to output the vector using cout << (*it) << endl;
I was a bit reluctant to put the full assignment question up on the forum but to avoid confusion here it is. I think i might be totally off track so any guidence will be appriciated.
Write a cpp program containing a class called VectorCollection that will be used to store a collection of vectors whose instances are of type string.
Write a single parameter constructor that receives an array of strings for initializing values in the collection.
Add functions to add instances to the collection, remove instances from the collection, delete all entries from the collection and display the entire collection.
Also overlad the * operator so that it returns the intersection of two VectorCollection objects.
Write a program to test all member functions and overloaded operators in your class.
Next, modify the main function so that instead of creating seperate variables for each Movie object, an array of at least 4 Movie objectsis created with sample data. Loop through the array and output the name, MPAA rating and average rating for each of the four movies.
//movies.h
//******************************************************************************************************
using namespace std;
#ifndef movies_H
#define movies_H
class VectorCollection
{
//member variables
string newtitle,newgentre,newmpaa,newrating;
vector<VectorCollection> movies;
public:
//function declarations
//default constructor
VectorCollection();
//overload constructor
VectorCollection(string,string,string,string);
//destructor
~VectorCollection();
void settitle(string);
void setgentre(string);
void setmpaa(string);
void setrating(string);
void display(vector<VectorCollection>);
};
#endif // MOVIES_H_INCLUDED
//movies.cpp
//******************************************************************************************************
//constructor definition
VectorCollection::VectorCollection()
{
}
//overloaded constructor def
VectorCollection::VectorCollection(string title,string gentre,string mpaa,string rating)
{
newtitle = title;
newgentre = gentre;
newmpaa = mpaa;
newrating = rating;
}
//destructor def
VectorCollection::~VectorCollection()
{
}
//mutator function
void VectorCollection::settitle(string title)
{
newtitle = title;
}
//mutator function
void VectorCollection::setgentre(string gentre)
{
newgentre = gentre;
}
//mutator function
void VectorCollection::setmpaa(string mpaa)
{
newmpaa = mpaa;
}
//mutator function
void VectorCollection::setrating(string rating)
{
newrating = rating;
}
void VectorCollection::display(vector<VectorCollection> movies)
{
vector<VectorCollection>::iterator it;
for ( it = movies.begin(); it < movies.end(); ++it)
{
//copy(movies.begin(),movies.end(),ostream_iterator<string>(cout," "));
cout << (*it) << endl;
}
}
//main.cpp
//******************************************************************************************************
#include <iostream>
#include <string>
#include "movies.h"
using namespace std;
int main()
{
string title,gentre,mpaa,rating;
vector<VectorCollection> movies;
movies.assign(4,VectorCollection());
VectorCollection *a_movie;
VectorCollection list;
for (int i = 0; i < 3; i++)
{
cout << "Enter the title : ";
cin >> title;
cout << "Enter the gentre: ";
cin >> gentre;
cout << "Enter the MPAA: ";
cin >> mpaa;
cout << "Enter the rating: ";
cin >> rating;
a_movie = new VectorCollection;
a_movie ->settitle(title);
a_movie ->setgentre(gentre);
a_movie ->setmpaa(mpaa);
a_movie ->setrating(rating);
movies.push_back(*a_movie);
cin.get();
}
list.display(movies);
return 0;
}
Besides all the other problems already pointed out, you have a std::vector<VectorCollection> in your VectorCollection class.
Standard containers cannot hold incomplete types. If you want to do this, you should have a vector of pointers to VectorCollection or use boost::ptr_vector which is designed specifically to hold pointers to classes.
Boost.Container will also allow you to do what you're trying.
You have a vector of VectorCollections. There is no << ostream operator for your VectorColections object defined. To be able to print contents of your own class using << operator you have to properly implement it for your class.
You may find an answer how to do it here:
How to properly overload the << operator for an ostream?
You need to provide an output stream operator for VectorCollection:
std::ostream& operator<<(std::ostream& os, const VectorCollection& v)
{
return os << "booh!";
}