C++ Populating a vector of objects with user input - c++

I am new to vectors and new to classes.That being said, I have found some posts about how to create a vector of objects. I want to know how would one go about creating a vector of objects from user input? Say the program asks the user to give the number of employees(class) he/she wants to create. The user wants to add 5 employees. So user must input the employee's last name and first name. I have a for loop in mind but I am not sure how to go about grabbing the user input (Maybe using getline and push_back?) and storing it in the vector.
//Lets say class.h looks like this
class Employee
{
private:
string lastName;
string firstName;
public:
void setLastname(string);
void setFirstname(string);
string getLastname() const;
string getFirstname() const;
}

Your Employee class should have a constructor. When gathering input, you need all the constructor arguments. Then, to add an Employee to a vector<Employee>, call employees.emplace_back( ctor-arguments ).

std::vector has a nice method called emplace_back, which
Appends a new element to the end of the container. The element is constructed through std::allocator_traits::construct, which typically uses placement-new to construct the element in-place at the location provided by the container.
So the only thing you are missing to be able to use it is an appropriate constructor.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Employee
{
private:
string firstName;
string lastName;
public:
void setLastname(string);
void setFirstname(string);
string getLastname() const{return lastName;}
string getFirstname() const{return firstName;}
//create a constructor
Employee(string firstName, string lastName)
: firstName(firstName), lastName(lastName)
{}
};
int main()
{
vector<Employee> emp;
int count = 0;
cout << "Enter the amount of employees to add:" << endl;
cin >> count;
string firstName, lastName;
for(int i = 0; i < count; ++i)
{
cout << "Please enter the first and last names" << endl;
cin >> firstName;
cin >> lastName;
emp.emplace_back(firstName, lastName);
}
for(const Employee & e : emp)
{
cout << "Employee:" << endl;
cout << e.getFirstname() << " " << e.getLastname() << endl;
}
}

Other users have provided a good examples explaining how to use emplace_back in modern C++.
If you work with pre-C++11 versions, there is no emplace_back method. In this case, you can collect data in your vector manually using old-style push_back. You can simply define a vector:
vector<Employee> employees;
Then, you can read your data line by line, create new objects, fill them according to your business logics and append to your vector:
int n;
int main()
{
cout << "Enter number of employyes: "; cin >> n;
for (int i = 0; i < n; i++)
{
std::string s;
Employee employee; // Create object
cout << "Employee " << i << ". First name: "; cin >> s;
employee.setFirstname(s); // Fill object
cout << "Employee " << i << ". Last name: "; cin >> s;
employee.setLastname(s); // Keep filling it
cout << "Welcome, " << employee.getFirstname() << " " << employee.getLastname() << endl;
employees.push_back(employee); // Add to vector
}
}
You can also define a constructor taking both firstname and lastname as arguments to make it easier to work with.

class Employee
{
private:
string lastName;
string firstName;
public:
Employee(string paramLastName, string paramFirstName) : lastName(move(paramLastName)), firstName(move(paramFirstName)) {}
void setLastname(string);
void setFirstname(string);
string getLastname() const;
string getFirstname() const;
}
You need a constructor that takes two strings as input. Obviously you could do without this but this reduces verbosity.
Employee(string paramLastName, string paramFirstName) :
lastName(move(paramLastName)), firstName(move(paramFirstName)) {}
You will need to call it in this way.
vector<Employee> inp;
string tmp1, tmp2;
while(std::cin>>tmp1 >> tmp2) {
inp.emplace_back(tmp1, tmp2);
}
(This is assuming that you will compile with c++11 support)

Related

C++ Storing a string into a class

I made a topic a bit ago regarding structs. And I know that classes have the same concept as structs. How would I go about storing a string into the class?
This is the class
class studentType
{
public:
void setData(string, int);
string getName() const;
int getId() const;
private:
string name;
int sid;
};
void studentType::setData(string, int) {
name = ??;
sid = ??;
}
string studentType::getName() const {
return name;
}
int studentType::getId() const {
return sid;
}
The main consists of:
int main() {
studentType object, number;
cout << "enter name and code of item1: ";
cin >> object.setData() >> object.setData();
cout << "enter name and code for item2: ";
cin >> number.setData() >> number.setData();
system("pause");
return 0;
}
How would I fix the cin issue? I already have string defined in the header. And yes, I know using namespace std; isn't preferred but it's for simplicity
int id;
string name;
cout << "enter name and code of item1: ";
cin >> name >> id;
object.setData(name, id);
cout << "enter name and code for item2: ";
cin >> name >> id;
object.setData(name, id);
You should instead use a constructor for your class though:
class studentType {
public:
studentType(string name, int sid)
: name(name)
, sid(sid)
{ }
// ...
You can then initialize your objects with the correct name and ID:
cin >> name >> id;
studentType object(name, id);
But I suppose constructors will come up very soon in the tutorial or course you're currently doing.
cin >> object.setData() >> object.setData();
the >> operator doesn't call object.setData; it takes a reference and sets the reference contents to the extracted input. The expression object.setData() calls the function, which returns void. Of course, the >> operator cannot take a void argument. Also, there aren't enough arguments in the funcall because object.setData expects a string and an int.
You should do this:
std::string name;
int num;
cin >> name >> num;
object.setData(name, num);
Your setData function can be as such:
void studentType::setData(string name, int sid) {
this->name = name;
this->sid = sid;
}
And in your main():
First cin the values and then call the setData function, i.e.
int main(){
string name;
int code;
studentType object, number;
cout << "enter name and code of item1: ";
cin >> name >> code;
object = studentType();
object.setData(name, code);
// your remaining code
}
Just a note of caution:
If you use cin to get the name and code, the name can only be a single word. Say if you are writing a name of two words, the first word will be put in name and the second will be attempted to put in code.
In simpler terms, cin is space-delimited.
What you're looking for is std::getline(). I would use cin for getting your integers, but not for the strings. I would separate the user input like this. Like #Suhaib Ahmad said, cin is space-delimited. To get a string including spaces from stdin, use std::getline().
void studentType::setData(string n, int i) {
this->name = n;
this->sid = i;
}
-
int main(void) {
string n;
int i;
studentType object, number;
cout << "Enter name for item1: ";
getline(cin, n);
cout << "Enter code for item1: ";
cin >> i;
object = studentType(); // make sure you construct your studentType, I also recommend using a constructor function
object.setData(n, i);
cout << "Enter name for item2: ";
getline(cin, n);
cout << "Enter code for item2: ";
cin >> i;
number = studentType();
number.setData(n, i);
system("pause");
return 0;
}
The way you are using setData(), with no arguments given, as a place to store the cin input is incorrect. You would need to declare variables first, and then initialize your class with the variables.

C++: I am confused on how add user input into a vector of a class

I have a class of customer
class customer{
private:
int customer_id;
string customer_name;
public:
customer(int id, string name);
//get set functions for id and name etc..
Then, I have a class that is a collection of the customer so
class customers{
private:
vector<customer> custVector;
public:
void add_cust(int id, string name);
void find_customer(int);
printCust();
};
The first thing I am trying to add is customers, so, I ask the user
void customers::add_cust(int id, string name)
{
int id;
string name;
cout << "Enter customer ID: ";
cin >> id;
custVector.push_back(id);
cout << "Enter customer Name: ";
cin >> name;
custVector.push_back(name);
}
Will that properly store the id and name of the customer into the vector or not?
I would compile my program but it has so many other errors right now that I wouldn't even know where to begin.
But then how would I print the info?
Would I need to have something in main like this
customers cust;
printCust(&cust);
to print out the info inside?
To add a customer to custVec all you need to do (assuming your constructor for customer is valid) is:
void customers::add_cust(int id, string name)
{
int id;
string name;
cout << "Enter customer ID: ";
cin >> id;
cout << "Enter customer Name: ";
cin >> name;
custVector.push_back(customer(id,name));
}
To answer your question about printing a customer's info, you can have a global function as you've defined, preferably a friend function (I'll leave that as research for you) such as:
void printCust(const customer& cst)
{
cout<<cst.getID()<<'\t'<<cst.getName();
}
Your definition for the vector does not match with what you are trying to add to it. Consider the definition:
vector<customer> custVector;
Whats being added to it is:
custVector.push_back(id); and custVector.push_back(name);
Where the id is an intand the name is a string instead of a customer object which you have defined your vector to contain.
To correct this define a constructor in your customer class which initializes a customer object
customer(int id, string name) : customer_id(id), customer_name(name) { }
In your add function you push the customer objects after getting the input as:
custVector.push_back(customer(id, name));
Also try getting hold of a good beginner c++ book.
It is not the responsibility of add_cust() to prompt the user for input. It is being passed input parameters from the caller. So, the parameters should be used as-is. The caller should handle prompting the user as needed, and then pass the input values to add_cust().
And no, the code you have shown won't work anyway. The constructor of the customer class requires 2 input parameters, but you are constructing 2 separate customer objects with 1 input value each.
Use something more like this instead:
void customers::add_cust(int id, string name)
{
custVector.push_back(customer(id, name));
}
Then the caller can do this:
customers cust;
...
int id;
string name;
cout << "Enter customer ID: ";
cin >> id;
cout << "Enter customer Name: ";
cin >> name;
cust.add_cust(id, name);
Then, to print the entries, simply call the class method you already defined:
cust.printCust();
Where the implementation may look like this:
void customers::printCust()
{
for(vector<customer>::iterator iter = custVector.begin(); iter != custVector.end(); ++iter) {
cout << "id: " << iter->getID() << ", name: " << iter->getName() << endl;
}
}

How to let a user add to and remove from "slots" in an array?

I have a project in my C++ class - we're supposed to make a "simple student management system" comprised of a class for the student attribute variables, and a main function with a branch statement that lets the user input names and IDs for the students. I know that I need to use an array to make "slots" for the students, and that my branch statements need to let the user input values into those slots, but I'm not exactly sure how to do it. Here is the code that I have so far.
#include <string>
#include <iostream>
#include <utility>
using std::string;
using std::cin;
using std::cout;
using std::endl;
struct Student {
private:
int id;
string name;
int birthday;
public:
Student()
{
id = 0;
birthday = 0;
}
Student(int id, string name, int birthday)
{
//set your parameters to the class variables
this->id = id;
this->name = name;
this->birthday = birthday;
}
void setID(int id)
{
this->id = id;
}
int getID() {
return id;
}
void setName(string name)
{
this->name = name;
}
string getName()
{
return name;
}
void setBirthday(int birthday)
{
this->birthday = birthday;
}
int getBirthday()
{
return birthday;
}
void output() {
cout << id << name << birthday << endl;
}
};
int main() {
Student arr[50];
cout << "Student Management System" << endl;
cout << "Press 'a' to add a student" << endl;
char a = 1;
int y = 1;
while (a == 'a') {
switch (y)
{
cout << "Input Student ID:";
cin >> id;
}
}
}
What I'm focusing on most is the fourth line from the bottom. I was told that I need to use my setters, so I said that I want what my user inputs to be treated as the value of the ID variable that I set in the class. However, when I wrote this out, I was given an error. Could someone tell me what the issue is?
You should try to get your switch statement working correctly. To use classes setters, you can store the user input to a temporary variable then from your one student you can call the member function. i.e. in your case:
arr[index].setID(tempInputVariable);
There is no id in your main function or as a global variable.
I suggest you overload operator >> to have your structure extract its members from the data stream:
struct Student
{
//...
public:
friend std::istream& operator>>(std::istream& input, Student& s);
};
std::istream& operator>>(std::istream& input, Student& s)
{
input >> s.id;
input >> s.name;
input >> s.birthday;
return input;
}
Although the above code doesn't use setters, it is the preferred method for inputting data.
The overload can be modified to use setters (kind of overkill):
std::istream& operator>>(std::istream& input, Student& s)
{
int id;
input >> id;
s.setID(id);
std::string name;
input >> name;
s.setName(name);
int birthday;
input >> birthday;
s.setBirthday(birthday);
return input;
}
If you don't like the overload, you can perform the steps in your main function:
//...
Student new_student;
//...
{
int student_id;
std::cout << "Input Student ID:";
std::cin >> student_id;
new_student.setID(student_id);
std::string student_name;
std::cout << "Input Student Name: ";
std::cin >> student_name;
new_student.setName(student_name);
int student_birthday;
std::cout << "Input Student Birthday: ";
std::cin >> student_birthday;
new_student.setBirthday(student_birthday);
}
Edit 1: The Database
You'll probably need to store or remember the students. This is easy using the first method above:
std::vector<Student> database;
Student s;
std::cout << "Enter student information (ID, Name and birthday, separated by spaces:\n";
std::cin >> s;
// Append to the database
database.push_back(s);
If you haven't learned std::vector you can try an array:
const size_t MAXIMUM_STUDENTS = 16;
Student database[MAXIMUM_STUDENTS];
size_t database_index = 0;
//...
Student s;
std::cout << "Enter student information (ID, Name and birthday, separated by spaces:\n";
std::cin >> s;
// Append to database
database[database_index] = s;
++database_index;

How do I use the ostream::seekp function to find an object with a certain id# in a random access file?

I have a Person class that has the private data members id, lastName, firstName, and age. I created file containing 50 Person objects with "unassigned" and 0 for the data members, using this function:
void createPersonFile(ofstream &outputPersonFile){
Person blankPerson;
blankPerson.setID(0);
blankPerson.setFirstName("unassigned");
blankPerson.setLastName("unassigned");
blankPerson.setAge(0);
for (int x = 0; x < 50; x++)
outputPersonFile.write(reinterpret_cast<const char *>(&blankPerson),
sizeof(Person));
}
I have to create functions that will let me write a new Person, update a Person, delete a Person, and display a Person but I don't know how to use the seekp function to write them. This is what I have for a function that will write a new Person to the file. I already have two separate functions not shown here that I am calling to open input/output files.
void writeNewPerson(ofstream &outputPersonFile){
int inputID;
int userNumber;
string userInput;
Person person;
cout << "Please enter a record number (1-50): ";
cin >> inputID;
cout << "Enter the person's first name: ";
cin >> userInput;
person.setFirstName(userInput);
cout << "Enter the person's last name: ";
cin >> userInput;
person.setLastName(userInput);
cout << "Enter the person's age: ";
cin >> userInput;
person.setAge(userNumber);
cout << endl;
outputPersonFile.seekp( WHAT GOES HERE??? );
outputPersonFile.write( reinterpret_cast<const char*>(&person), sizeof(Person) );
}
I'm stumped on how to use the seekp function above...
Person.h
// Person.h
// Class Person definition
#ifndef PERSON_H
#define PERSON_H
#include <string>
using namespace std;
class Person
{
public:
// default Person constructor
Person(int = 0, string = "unassigned", string = "unassigned", int = 0);
// accessor functions for id
void setID(int);
int getID() const;
// accessor functions for lastName
void setLastName(string);
string getLastName() const;
// accessor functions for firstName
void setFirstName(string);
string getFirstName() const;
// accessor functions for age
void setAge(int);
int getAge() const;
private:
int id;
char lastName[15];
char firstName[15];
int age;
}; // end class Person
#endif

Output comes out wrong

I am teaching myself C/C++ at the moment, and I got the exercise (from the book I am reading) to write a program that could make an output like this:
Enter your first name: Flip
Enter your last name: Fleming
Here’s the information in a single string: Fleming, Flip
Using Structures. But my output comes out like this:
Enter your first name: Flip
Enter your last name: Fleming
Here’s the information in a single string: ,
Here is the code. It's fairly short and simple so it shouldn't be hard to read :)
#include <iostream>
#include <cstring>
using namespace std;
struct Person {
char* firstName;
char* lastName;
};
char* getName(void);
int main() {
Person* ps = new Person;
cout << "Enter your first name: ";
char* name;
name = getName();
ps->firstName = name;
cout << "Enter your last name: ";
char* lastname;
lastname = getName();
ps->lastName = lastname;
cout << "Here's the information in a single string: "
<< ps->lastName << ", " << ps->firstName;
delete ps;
delete name;
delete lastname;
return 0;
}
char* getName() {
char temp[100];
cin >> temp;
cin.getline(temp, 100);
char* pn = new char[strlen(temp) + 1];
strcpy(pn, temp);
return pn;
}
First, there's no such thing as C/C++. You're mixing them, which is wrong. Since you're using C++ headers/new/using, I'll assume you want C++, so here's how you fix your code:
replace all char* and char[] with std::string
get rid of dynamic allocation
So, some changes would be:
struct Person {
std::string firstName;
std::string lastName;
};
or
Person ps;
You are using:
cin >> temp;
cin.getline(temp, 100);
You probably overwrite what you already have with empty string at the end of a line.
Use just one of them.
If you'll stick with using cin >> you may consider setting width() to prevent buffer overflow.
First, the immediate problem is that you read twice from std::cin: first with operator>>, and then with getline. Pick one or the other.
But let's simplify your code a bit. There are simply too many sources of error. Pointers are tricky because they might point to the wrong thing, or you might forget to delete objects, or delete them twice. C-style char arrays as strings are bad because, well, they're not strings, and they don't behave like strings.
So let's use the standard library's string class:
#include <iostream>
#include <string>
struct Person {
std::string firstName;
std::string lastName;
};
std::string getName(void);
int main() {
Person ps;
cout << "Enter your first name: ";
std::string name = getName();
ps.firstName = name;
cout << "Enter your last name: ";
std::string lastname = getName();
ps.lastName = lastname;
cout << "Here's the information in a single string: "
<< ps.lastName << ", " << ps.firstName;
}
std::string getName() {
std::string temp;
std::getline(cin, temp);
return temp;
}
This is a fairly simple, almost mechanical substitution, basically just replacing char* by std::string, and removing the bits that are no longer necessary.
Of course, as pointed out in a comment, I've omitted all forms of error checking, which a real program should definitely do.
No no no, wayyyy too complicated. Use real C++ idioms. The program could be as simple as this:
#include <string>
#include <iostream>
int main()
{
std::string firstName, lastName;
if (!(std::cout << "Your first name: " &&
std::getline(std::cin, firstName) &&
std::cout << "Your last name: " &&
std::getline(std::cin, lastName) ))
{
std::cerr << "Error: unexpected end of input!\n";
return 0;
}
std::cout << "You are " << firstName << " " << lastName << ".\n";
}
As a variation on the theme, you could put each getline in a loop until the user inputs a non-empty line:
std::cout >> "Your first name: ";
for ( ; ; )
{
if (!(std::getline(std::cin, firstName))
{
std::cerr << "Error: unexpected end of input.\n";
return 0;
}
if (!firstName.empty())
{
break;
}
std::cout << "Sorry, please repeat - your first name: ";
}