How do I go about printing a vector of objects? - c++

I'm guessing I might have to use pointers, but haven't gone in depth too much on them in class yet to try and implement them in my program. I have this so far, the printing function is towards the middle of the program. I'm not quite sure on how to print out the elements from the vector as my approach didn't work.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class rolodex
{
string name;
string street, town, state;
string zip;
string phone;
vector <rolodex> entries;
public:
rolodex();
void getmenu();
void add_entry();
void set_name();
void set_address();
void set_phone();
void printinfo();
};
rolodex :: rolodex() : name(""), street(""), town(""), state(""), zip(""),
phone(""), entries()
{
}
void rolodex :: getmenu()
{
cout << "\n\n1)Add Entry";
cout << "\n5)Print All Entries";
cout << "\n6)Exit" << endl;
}
void rolodex :: add_entry()
{
rolodex temp;
cout << "\n\nEnter Name: ";
temp.set_name();
temp.set_address();
cout << "\n\nEnter Your Phone Number: ";
temp.set_phone();
entries.push_back(temp);
}
void rolodex :: set_name()
{
cin.ignore();
getline(cin, name);
}
void rolodex :: set_address()
{
cout << "\n\nNow we'll enter address information.";
cout << "\n\nStreet: ";
getline(cin, street);
cout << "\n\nTown: ";
getline(cin, town);
cout << "\n\nState: ";
getline(cin, state);
cout << "\n\nZip: ";
getline(cin, zip);
}
void rolodex :: set_phone()
{
getline(cin, phone);
}
void rolodex :: printinfo()
{
for(unsigned int i = 0; i < entries.size(); i++)
{
cout << entries[i] << endl; //This is where I'm stuck since I've only
//worked with vectors of non-object data
//type
}
}
int main()
{
rolodex person, menu;
short choice;
bool done = false;
do
{
menu.getmenu();
cout << "\n\nEnter a choice: ";
cin >> choice;
switch(choice)
{
case 1:
person.add_entry();
break;
case 5:
person.printinfo();
break;
case 6:
done = true;
break;
default:
cout << "\n\nInvalid Entry." << endl << endl;
}
} while(!done && isdigit(choice));
return 0;
}

πάντα ῥεῖ is right, but to add a little more detail...
You need to specify how you want the stream to handle your object. This is done by by adding a << operator. For example:
std::ostream& operator<<(std::ostream& s, const rolodex& r){
// Or however you want to format it.
s << "Name: " << r.name << " : ";
s << "Street: " << r.street << " : ";
s << "Town: " << r.town << " : ";
s << "State: " << r.state << " : ";
s << "Zip: " << r.zip << "\n";
}
Unfortunately, the function above tries to access the private fields of your class, which it can't because it is not part of the class definition.
An easy way to address that is to declare this function a "friend" inside of the class definition, like such:
friend std::ostream& operator<<(std::ostream&, const rolodex&);
...And since you might appreciate it, one big copy-pasteable chunk that you can use directly that should make your function work:
class rolodex
{
string name;
string street, town, state;
string zip;
string phone;
vector <rolodex> entries;
public:
rolodex();
void getmenu();
void add_entry();
void set_name();
void set_address();
void set_phone();
void printinfo();
friend std::ostream& operator<<(std::ostream&, const rolodex&);
};
std::ostream& operator<<(std::ostream& s, const rolodex& r){
// Or however you want to format it.
s << "Name: " << r.name << " : ";
s << "Street: " << r.street << " : ";
s << "Town: " << r.town << " : ";
s << "State: " << r.state << " : ";
s << "Zip: " << r.zip << "\n";
}

Following up on πάντα ῥεῖ's suggestion, here's one way of doing that, changing your design as little as possible:
1) Create a non-member overloaded operator<< for your rolodex class:
std::ostream& operator<< (std::ostream& os, const rolodex& rol)
{
os << rol.name << ":" << std::endl
<< "\t" << rol.street << std::endl
<< "\t" << rol.town << std::endl
<< "\t" << rol.state << std::endl
<< "\t" << rol.zip << std::endl
<< "\t" << rol.phone << std::endl;
return os;
}
.. but the compiler will chide you for attempting to access private members (by default, members are private) from outside the class, so you would have to relax the rules a bit:
class rolodex
{
...
public:
...
friend std::ostream& operator<< (std::ostream& os, const rolodex& rol);
};
You can't have the operator<< inside the class itself, see does-overloading-operator-works-inside-the-class.
However, it is almost always better design to add getter functions to your public interface anyway. You would have get_name() etc in the public: section of your class def, those functions would initially just return the values of the private member variables, and then your operator<< can use them instead of trying to access the private members. You then no longer require the friend declaration.
I upvoted Some programmer dude's remark about your design
The code for letting the use input the data really shouldn't be inside the rolodex class, because it makes the class hard to reuse. Image wanting to re-use the rolodex from a graphical interface, for example, and it's not such a good idea to have the rolodex contain instances of itself inside the vector.
I would suggest a
1) Person class containing all the person's attributes, with public getters get_name() and setters set_name() that don't use a specific entry method, just take the data as arguments e.g. set_name(std::string& name).
2) an non-member operator<< to output a person to an output stream
3) a Rolodex class with a private std::vector<Person> and methods to add a person, write all the persons to an output stream, etc..
Good luck & enjoy :-)
Edit: the menu structure on the terminal should IMHO be left inside the main() function or encapsulated into another class. But certainly don't leave it in Rolodex or worse, Person.

Related

How do I call a function with a STL iterator to work? [duplicate]

I have created a Vector of pointers to a class called Food
vector<Food*> items;
The class looks like the following:
class Food
{
private:
string name;
int month;
int year;
public:
void display()
{
cout << name << " - " << month << "/" << year << endl;
}
}
I then have created a function to prompt these items
void promptInventory(vector<Food*> &items)
{
string name;
int month;
int year;
do
{
cout << "Enter item name: ";
getline(cin, name);
if (name != "quit")
{
cout << "Enter expiration month: ";
cin >> month;
cout << "Enter expiration year: ";
cin >> year;
cin.ignore();
Food * food = new Food;;
food->setName(name);
food->setMonth(month);
food->setYear(year);
items.push_back(food);
}
}
while (name != "quit);
I'd like to iterate through the vector of pointers and call the display function for all the items but I am unable to dereference them using iterators.
How would I be able to sucessfully iterate through these pointers and call the display function?
Unfortunately,
vector<Food*>::iterator iter = items.begin();
while (iter < items.end())
{
cout << *iter->display() << endl;
}
Results in:
error: request for member ‘display’ in ‘* iter.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator-><Food**, std::vector<Food*> >()’, which is of pointer type ‘Food*’ (maybe you meant to use ‘->’ ?)
cout << *iter->display() << endl;
Thank you!
Operator Precedence has got you. *iter->display() is interpreted by the compiler as *(iter->display()) because -> has precedence over (will execute before) *. A cleaner way to look at this is *((*iter).display())
Dereference iterator to a Food *.
Attempt to invoke display on the Food*. Fails and results in the compiler error.
Dereference the result of the call to display.
You need to force the execution ordering you want with some brackets: (*iter)->display()
Dereference iterator to a Food *
Dereference again to a Food
Invoke display on the Food
Fixing this leads to problem 2: display doesn't return anything that can be written to cout. Fortunately, display does all the printing that is required.
while (iter < items.end())
{
(*iter)->display();
}
resolves that problem, but in idiomatic C++ there is a better solution: overload the << operator.
Food picks up a friend function
class Food
{
private:
string name;
int month;
int year;
public:
void display()
{
cout << name << " - " << month << "/" << year << endl;
}
friend ostream & operator<<(ostream & out, const Food & food)
{
out << food.name << " - " << food.month << "/" << food.year;
return out;
}
};
Then you can
vector<Food*>::iterator iter = items.begin();
while (iter < items.end())
{
cout << **iter << endl;
}
or with a range-based for loop
for (auto & item:items)
{
cout << *item << endl;
}
Side note: In addition to practicing pointers, practice Smart Pointers. You'll find them much more useful.

Adding Setters to a function template

I am trying to add setter to my project as a requirement but am stuck on making it work. I commented out the areas I have to add it but everything I have looked up has not worked. I know I am close but everything seems to not work.
#include "pch.h"
#include <string>
#include <conio.h>
#include <iostream>
using namespace std;
template <class T>
class Holder
{
private:
T thing;
int number; //add an integer data member that stores the number of data members of whatever class is stored in "thing"
public:
void standardInput();
void standardOutput();
void setNumber(int); // declare a setter function for the new data member
};
template <class T>
void Holder<T>::standardInput()
{
cout << endl;
cout << "You will be asked to enter " << n.setNumber << " items" << endl; // a line of output that use the data member with the number
cin >> Holder<T>::thing;
}
template <class T>
void Holder<T>::standardOutput()
{
cout << endl;
cout << "Here's the data you requested: " << endl;
cout << Holder<T>::thing << endl;
}
template<class T>
void Holder<T>::setNumber(int n) //implement the setter function for the new data member
{
setNumber = n;
}
// This is the first of two custom classes
class Student
{
friend ostream& operator<<(ostream&, Student&);
friend istream& operator>>(istream&, Student&);
private:
string name;
double tuiton;
};
ostream& operator<<(ostream& out, Student& a)
{
out << "The Student " << a.name << " Tuiton is: " << a.tuiton << endl;
return out;
}
istream& operator>>(istream& in, Student& a)
{
cout << "Enter the name of student: ";
in >> a.name;
cout << "What is the Price of tuiton? ";
in >> a.tuiton;
return in;
}
// This is the second of two custom classes
class FastFood
{
friend ostream& operator<<(ostream&, FastFood&);
friend istream& operator>>(istream&, FastFood&);
private:
int valueNumber;
double cost;
};
ostream& operator<<(ostream& out, FastFood& a)
{
out << " The Combo Number is " << a.valueNumber << " .It costs " << a.cost << endl;
return out;
}
istream& operator>>(istream& in, FastFood& a)
{
cout << "What is the Combo number? ";
in >> a.valueNumber;
cout << "Enter cost: ";
in >> a.cost;
return in;
}
int main()
{
cout << "For an integer: " << endl;
Holder<int> val;
// use the setter to store 1.
val.standardInput();
val.standardOutput();
cout << "For a Student:" << endl;
Holder<Student> aCollegeStudent;
// use the setter to store 2.
aCollegeStudent.standardInput();
aCollegeStudent.standardOutput();
Holder<FastFood> vMeal;
// use the setter to store 3.
vMeal.standardInput();
vMeal.standardOutput();
cout << endl;
system("pause");
return 0;
}
This is supposed to ask the integer along with the student and fastfood information. I required to add a setter in the template but wont need to use a getter due to standard input and output just cant figure out the right way to do it.

C++ output all members in a object

So far I have defined a simple class...
class person {
public:
string firstname;
string lastname;
string age;
string pstcode;
};
...then added some members and values to an object named "bill"...
int main() {
person bill;
bill.firstname = "Bill";
bill.lastname = "Smith";
bill.age = "24";
bill.pstcode = "OX29 8DJ";
}
But how would you simply output all those values? Would you use a for loop to iterate over each member?
I typically override operator <<, so that my objects are as easy to print as any built-in object.
Here is one way to override operator <<:
std::ostream& operator<<(std::ostream& os, const person& p)
{
return os << "("
<< p.lastname << ", "
<< p.firstname << ": "
<< p.age << ", "
<< p.pstcode
<< ")";
}
And then to use it:
std::cout << "Meet my friend, " << bill << "\n";
Here is a complete program using this technique:
#include <iostream>
#include <string>
class person {
public:
std::string firstname;
std::string lastname;
std::string age;
std::string pstcode;
friend std::ostream& operator<<(std::ostream& os, const person& p)
{
return os << "("
<< p.lastname << ", "
<< p.firstname << ": "
<< p.age << ", "
<< p.pstcode
<< ")";
}
};
int main() {
person bill;
bill.firstname = "Bill";
bill.lastname = "Smith";
bill.age = "24";
bill.pstcode = "OX29 8DJ";
std::cout << "Meet my friend, " << bill << "\n";
}
Simplistically, you output each element using an ostream:
class Person
{
public:
void Print_As_CSV(std::ostream& output)
{
output << firstname << ",";
output << lastname << ",";
output << age << ",";
output << pstcode << "\n";
}
string firstname;
string lastname;
string age;
string pstcode;
};
There may be different methods of printing, which is why I didn't overload operator <<. For example, one data member per line would be another popular scenario.
Edit 1: Why not looping?
The class has separate fields, which is why you can't iterate over the members.
If you want to iterator or loop over the members, you either have to have an iterator for your class or use a container, such as std::vector, that provides iteration.

Writing information in a structure to a file

Alright so i have these two structures, Im sending them down to a function to be saved to a txt file.
struct Cost
{
double hours;
double cost;
double costFood;
double costSupplies;
};
struct Creatures
{
char name[50];
char description[200];
double length;
double height;
char location[100];
bool dangerous;
Cost management;
};
This is the part of the function im confused on, i don't know how to take each line of this structure and write it to the file. Can someone explain to me how to do this?
file.open(fileName, ios::out);
if (!file)
{
cout << fileName << " could not be opened." << endl << endl;
}
else
{
fileName << c.name
<< c.description
<< c.lenght
<< c.height
<< c.location
<< c.dangerious
<< c.management.hours
<< c.management.cost
<< c.management.costFood
<< c.management.costSupplies;
file.close();
cout << "Your creatures where successfully save to the " << fileName << " file." << endl << endl
<< "GOODBYE!" << endl << endl;
}
}
If you want a solution like what you wrote in your question all you need to do is put and end line after each attribute you write out.
fileName << c.name << std::endl
<< c.description << std::endl
...
As long as the information you were trying to output is all that is going in the file this should work.
Then you can read them back in in the order you wrote them. Just be careful when reading back in strings which might have spaces in them.
You need to write the overloaded operator << for your defined classes Cost and Creatures.
class Cost {
public:
friend std::ostream& operator<< (std::ostream& o, const Cost& c);
// ...
private:
// data member of Cost class
};
std::ostream& operator<< (std::ostream& o, const Cost& c)
{
return o << c.hours<<"\t"<<c.cost<<"\t"<<c.costFood<<"\t"<<c.costSupplies<<std""endl;
}
Now you can use it as follows:
Cost c;
std::cout<<c<<"\n";
For detailed information about this concept, you can refer the ISOCPP FAQ link on this
http://isocpp.org/wiki/faq/input-output#output-operator

Enumerations and User Input

I was wondering if enumeration is commonly used with user input. I'm doing an exercise in which in my Book class I have to create an enum Genre with different genre enumerators such as fiction, non, fiction etc.
When the user uses the program, he/she is asked for certain information about the book being stored. For a genre, normally I would just do this with a string function and restrict it to certain names with if statements.
However, I'm not sure how to accomplish the same process with an enumerated type, nor do I know if it's even supposed to be used for that sort of thing. Here is the code if you're interested.
#include "std_lib_facilities.h"
//Classes-----------------------------------------------------------------------
class Book{
public:
Book(){}; // default constructor
//operators
friend ostream& operator<<(ostream& out, const Book& val);
bool Book::operator==(const Book& check)
//enumerators
enum Genre{
fiction, nonfiction, periodical, biography, children};
//member functions
string title();
string author();
int copyright();
void ISBN();
bool checkout();
private:
string title_;
string author_;
int copyright_;
int ISBN1;
int ISBN2;
int ISBN3;
char ISBN4;
bool checkout_;
};
// Error Function---------------------------------------------------------------
void _error(const string& s)
{
cout << endl;
cout << "Error: " << s << endl;
cout << endl;
}
// Member Functions-------------------------------------------------------------
string Book::title()
{
cout << "Title: ";
getline(cin,title_);
cout << endl;
return title_;
}
string Book::author()
{
cout << "Author: ";
getline(cin,author_);
cout << endl;
return author_;
}
int Book::copyright()
{
cout << "Copyright: ";
cin >> copyright_;
cout << endl;
return copyright_;
}
void Book::ISBN()
{
cout << "ISBN (Use spaces): ";
cin >> ISBN1 >> ISBN2 >> ISBN3 >> ISBN4;
if((ISBN1<0) || (ISBN2<0) || (ISBN3<0) || (ISBN1>9) || (ISBN2>9) || (ISBN3)>9)
_error("Must be single digit.");
else if(!isdigit(ISBN4) && !isalpha(ISBN4))
_error("Must be single digit or letter.");
else{ cout << endl;
return;}
}
bool Book::checkout()
{
char check;
cout << "Checked out?(Y or N): ";
cin >> check;
switch(check){
case 'Y':
cout << endl;
return true;
break;
case 'N':
cout << endl;
return false;
break;
default:
_error("Must be Y or N.");}
}
// Operator Overloads-----------------------------------------------------------
ostream& operator<<(ostream& out, const Book& val){
out << "Title: " << val.title_ << endl;
out << "Author: " << val.author_ << endl;
out << "ISBN: " << val.ISBN1 << "-" << val.ISBN2 << "-" << val.ISBN3 << "-" << val.ISBN4 << endl;
out << endl;
return out;}
bool Book::operator==(const Book& check){
return((ISBN1 == check.ISBN1) && (ISBN2 == check.ISBN2) && (ISBN3 == check.ISBN3)
&& (ISBN4 == check.ISBN4));}
// Main-------------------------------------------------------------------------
int main()
{
bool finished = false;
char notfinished;
while(!finished)
{
Book book;
book.title();
book.author();
book.copyright();
book.ISBN();
book.checkout();
cout << "Do you wish to store another book?(Y or N): ";
cin >> notfinished;
if(notfinished == 'Y'){
cin.ignore();
cout << endl;}
else if(notfinished == 'N') finished = true;
else _error("Must be Y or N");
}
keep_window_open();
}
Note that some things aren't being used at the moment because the feature they are a part of hasn't been fully implemented yet (storing in a library, outputting books, etc.)
So what would it take to accept user input for the enumerators listed, if even possible? I was thinking something along the lines of making a Genre variable. Then having a function where the user inputs for cin>>variable. However, I'm guessing that the function wouldn't understand an input like 'fiction' and would only accept the enumerator values and input.
Make Genre a class that wraps the enum type (GenreTypeEnum). Add the necessary operators, e.g. istream, ostream, equal operator, etc.
Inside the istream operator, you can read a std::string from the stream and then parse and convert the value to the associated GenreTypeEnum.
Something like this perhaps:
namespace GenreType { enum GenreTypeEnum { miscellaneous, fiction, non_fiction, children }; }
class Genre
{
public:
Genre() : genreType( GenreType::miscellaneous) {}
~Genre() {}
void setType( std::string genreTypeString ){ // implement string-> enum }
std::string toString( void ) const { // convert genre back to string }
private:
GenreType::GenreTypeEnum genreType;
};
std::ostream& operator<<( std::ostream& os, const Genre& genre )
{
os << genre.toString();
return os;
}
std::istream& operator>>( std::istream& is, Genre& genre )
{
std::string input;
is >> input;
genre.setType( input );
return is;
}
C-style enums are not terribly useful for this purpose, since there's no way to recover the original string name. You could make some switch-based mechanism, but at that point you may as well just set up your own way of doing it all that works with your user I/O requirements without shoehorning.
One of the ways to handle this is to set up a map of strings to enum values. Other possibilities include a dedicated function.
See this question for some ideas.
This question has some ideas of how to generate code to convert enums to strings, but most of the examples will work in reverse as well.