Here I'm trying to overwrite the inventory objects, but when I run the second std::cout it print the old value again, I want it to write the inputted value.
#include <iostream>
#include <string>
class inventory
{
private:
std::string item;
int onhand;
double cost;
public:
inventory(std::string i, int o, double c){
item = i;
onhand = o;
cost = c;
}
friend std::ostream& operator<<(std::ostream& stream, inventory entity){
stream << entity.item << "\t" << entity.onhand << "\t" << entity.cost << std::endl;
return stream;
}
friend std::istream& operator>>(std::istream& stream, inventory entity){
stream >> entity.item >> entity.onhand >> entity.cost;
return stream;
}
};
int main()
{
inventory obj("hammer", 12, 2000);
std::cout << obj;
std::cin >> obj;
std::cout << obj;
return 0;
}
The problem you're facing is, that you pass your inventory obj by value
What you want is passing it as reference like so:
friend std::istream& operator>>(std::istream& stream, inventory &entity)
Your operator>> accepts a copy of object and modifies that copy. You need to pass by reference:
friend std::istream& operator>>(std::istream& stream, inventory entity);
Related
Sorry if this question has been asked before, but I'm struggling with overloading the << operator to stream different data into multiple files.
I have a Player class, which has the following attributes:
char* name;
char* password;
int hScore;
int totalGames;
int totalScore;
int avgScore;
I want to overload the << operator twice: one to stream the name, password and hScore to a "Players.txt" file, and a second overload to stream the totalGames, totalScore and avgScore to a different .txt file which is based off each player's name, e.g. "Player1.txt".
Here's what my operator looks like in the Player class:
friend ostream& operator<< (std::ostream& os, Player& player)
{
os << player.name << "\n" << player.encryptPassword((player.password), 3) << "\n" << player.hScore << "\n";
return os;
}
And here's where I am calling it, from a PlayerLibrary class which contains a vector of Players:
ofstream out("Yahtzee.txt");
if (out.is_open())
{
for_each(playerList.begin(), playerList.end(), [&out](Player* player) {out << (*player);});
}
else
{
cout << "THERE WAS AN ERROR WRITING TO FILE\n";
}
Basically, I want to stream the other variables into another file which is named after the player name, and contains a scorecard for each game they've played. So far it looks like:
for (auto it = playerList.begin(); it != playerList.end(); ++it)
{
auto position = it - playerList.begin();
string filename(playerList[position]->getName());
filename = filename + ".txt";
ofstream out2(filename);
for (int i = 0; i < playerList[position]->getNumberOfScorecards(); i++)
{
out2 << *playerList[position]->getScorecard(i);
}
}
This only streams the scorecard and not the totalGames, totalScore and avgScore, like I want it to.
I have tried just moving those variables into the scorecard class, but I feel that it makes more sense to have them where they are.
I understand that I can't overload operator<< twice if both overloads have the same parameters, is there another way of going about this? Is there anyway perhaps in the overloaded function to use the output stream and check the name of the .txt file or something.
Hope the question makes sense.
Rather than defining an operator<< for Player itself, create a couple of utility types that refer to the Player and have their own operator<<s, let them decide which portions of the Player to stream, eg:
class Player
{
private:
std::string name;
std::string password;
int hScore;
int totalGames;
int totalScore;
int avgScore;
...
public:
...
std::string getName{} const { return name; }
...
std::string EncryptPassword(int arg) const { return ...; }
int getNumberOfScorecards() const { return ...; }
Scorecard* getScorecard(int index) const { return ...; }
class Info
{
const Player &m_player;
void print(std::ostream &os) const {
os << m_player.name << "\n" << m_player.encryptPassword(3) << "\n" << m_player.hScore << "\n";
}
public:
Info(const Player &player) : m_player(player) {}
friend std::ostream& operator<<(std::ostream &os, const Info &info)
{
info.print(os);
return os;
}
};
friend class Info;
struct Stats
{
const Player &m_player;
void print(std::ostream &os) const
{
os << m_player.totalGames << "\n" << m_player.totalScore << "\n" << m_player.avgScore << "\n";
}
public:
Stats(const Player &player) : m_player(player) {}
friend std::ostream& operator<<(std::ostream &os, const Stats &stats)
{
stats.print(os);
return os;
}
};
friend class Stats;
};
And then you can use them like this:
ofstream out("Yahtzee.txt");
if (out.is_open())
{
for(auto *player : playerList)
out << Player::Info(*player);
}
else
{
cout << "THERE WAS AN ERROR WRITING TO FILE\n";
}
for (auto *player : playerList)
{
ofstream out2(player->getName() + ".txt");
out2 << Player::Stats(*player);
for (int i = 0; i < player->getNumberOfScorecards(); ++i)
{
out2 << *player->getScorecard(i);
}
}
Online Demo
The code runs, but I cannot get cout to work. Please help me, I am a beginner, and really struggling with getting the contents of my array to output.
cout << myArray[0].getSquareName(); is the line that never cout's.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class cSquare {
public:
string SquareName;
string getSquareName() const;
void setSquareName(string);
friend std::istream & operator >> (std::istream & is, cSquare & s);
};
// set method
void cSquare::setSquareName(string squareName)
{
squareName = SquareName;
}
//square name get method
string cSquare::getSquareName() const
{
return SquareName;
}
ostream & operator << (ostream & os, const cSquare & s)
{
os << s.getSquareName() << ' ';
return os;
}
istream & operator >> (istream & is, cSquare & s)
{
is >> s.SquareName;
return is;
}
int main()
{
string discard;
int i = 0;
const int MAX_SIZE = 26;
ifstream monopoly("monopoly.txt", ios::in);
if (monopoly.is_open())
{
cSquare myArray[MAX_SIZE];
getline(monopoly, discard);
string sname; //string to store what I read in from my file
while (i < MAX_SIZE && monopoly >> sname)
{
myArray[i].setSquareName(sname);//stores the string read in into the array
cout << myArray[0].getSquareName(); //it never cout's this
i++;
}
}
}
Your setSquareName() method is assigning the object's SquareName member to the input parameter, which is wrong. You need to do the opposite instead, eg:
void cSquare::setSquareName(string sname)
{
//sname = SquareName;
SquareName = sname;
}
Also, this line:
cout << myArray[0].getSquareName();
Should be this instead:
cout << myArray[i];
With those 2 changes, the code works.
Demo
I'm making a small program that contains a user defined class that contains obects object of struct type date and time. The struct date contains a string type. How can i serialize the containing object entry so as to be able to store the entry object in a file as well as to read from it in c++?
Here is my minimal code:
#include<iostream>
#include<fstream>
#include<string>
#define s ' ' //defining space character
using namespace std;
struct date{
int day;
string month;
int year;
};
struct time{
int hr;
int min;
};
class entry{
private:
date d;
time t;
int sno=0;
public:
void incrementsno(){++sno;}
void getdate(){ //This function gets date
cout<<"\nEnter the date : ";
cout<<"\nDay : ";
cin>>d.day;
cout<<"Month : ";
cin>>d.month;
cout<<"Year :";
cin>>d.year;
}
void gettime(){ //This function gets time
cout<<"\n\nEnter time : ";
cout<<"\nHours :";
cin>>t.hr;
cout<<"Minutes :";
cin>>t.min;
}
};
int main(){
//declaring variables
char c;
string filename;
entry e;
ifstream filer;
ofstream filew;
//getting file name begins
cout<<"Enter the name of file you want to create : ";
cin>>filename;
cout<<"\nThe file name is : "<<filename<<endl;
//getting file name over
//creating and opening file
filew.open(filename.c_str(),ios::binary|ios::out|ios::app);
//file association operation successful
cout<<"\nDo you want to write to file? : ";
cin>>c;
if(c=='y')//Entering date and time
{
do{
e.getdate();
e.gettime();
filew.write((char*)&e,sizeof(e));
cout<<"\nFile write operation successful.\n";
e.incrementsno();
cout<<"\nDo you wish to continue? :";
cin>>c;
}
while(c=='y');
}
else
cout<<"\nReading file...\n";
filew.close();
filer.open(filename.c_str(),ios::binary|ios::in); //opening file for reading
while(filer.read((char*)&e,sizeof(e)))
{
e.showdate();
e.showtime();
}
cout<<"\n\nFile IO successful...";
filer.close();
return 0;
}
This is a non-working, halfmeasure streaming framework based on the comments. It does NOT work - it's something to work with.
#include <iostream>
#include <string>
#include <vector>
//-----------------------------------------------------------------------------
struct Date {
int day;
std::string month;
int year;
};
// Date serializing support:
// stream out a Date to a generic stream (like a file)
std::ostream& operator<<(std::ostream& os, const Date& d) {
return os << d.day << '\n' << d.month << '\n' << d.year << '\n';
}
// read a Date from a generic stream (like a file)
std::istream& operator>>(std::istream& is, Date& d) {
return is >> d.day >> d.month >> d.year;
}
// Date adapters for human interaction - only holds references to "real" objects
struct DateUIout {
explicit DateUIout(const Date& d) : date(d) {}
// DateUIout(const Date&) = delete; // not copyable - but made it explicitly
// clear
// holds a reference to the Date struct we'd like to work with
// and an output stream for asking the user questions if needed
const Date& date;
};
std::ostream& operator<<(std::ostream& os, const DateUIout& dui) {
const Date& d = dui.date; // alias to the Date we'd like to work with
return os << "Day: " << d.day << " Month: " << d.month << " Year: " << d.year
<< '\n';
}
struct DateUIin {
explicit DateUIin(Date& d, std::ostream& qs = std::cout) :
date(d), questions(qs) {}
DateUIin(const Date&) = delete; // not copyable - but made it explicitly clear
Date& date;
std::ostream& questions; // used for printing questions to humans
};
std::istream& operator>>(std::istream& is, DateUIin& dui) {
Date& d = dui.date; // alias to the Date we'd like to work with
dui.questions << "Enter the date:\n"
<< " Day: ";
is >> d.day;
dui.questions << " Month: ";
is >> d.month;
dui.questions << " Year: ";
return is >> d.year;
}
//-----------------------------------------------------------------------------
struct Time {
int hr;
int min;
};
// Time serializing support: (much like everything in Date)
// stream out a Time
std::ostream& operator<<(std::ostream& os, const Time& t) {
return os << t.hr << '\n' << t.min << '\n';
}
// read a Time from a stream
std::istream& operator>>(std::istream& is, Time& t) {
return is >> t.hr >> t.min;
}
// Time adapter for human interaction - only holds references to "real" objects
struct TimeUI {
explicit TimeUI(Time& t, std::ostream& qs = std::cout) : tim(t), questions(qs) {}
Time& tim;
std::ostream& questions;
};
std::ostream& operator<<(std::ostream& os, const TimeUI& tui) {
Time& t = tui.tim;
return os << "Hour: " << t.hr << ' ' << t.min << '\n';
}
std::istream& operator>>(std::istream& is, TimeUI& tui) {
Time& t = tui.tim;
tui.questions << "Enter the time:\n Hour: ";
is >> t.hr;
tui.questions << " Minute: ";
return is >> t.min;
}
//-----------------------------------------------------------------------------
struct Timestamp {
Date date{};
Time time{};
};
// Timestamp serializing support:
// stream out a Timestamp
std::ostream& operator<<(std::ostream& os, const Timestamp& ts) {
return os << ts.date << ts.time;
}
// read a Timestamp from a stream
std::istream& operator>>(std::istream& is, Timestamp& ts) {
return is >> ts.date >> ts.time;
}
// Timestamp adapter for human interaction - only holds references to "real" objects
struct TimestampUIout {
TimestampUIout(const Timestamp& Ts) : ts(Ts) {}
// TimestampUIout(const TimestampUI&) = delete;
Timestamp& ts;
};
std::ostream& operator<<(std::ostream& os, const TimestampUIout& tsui) {
return os << DateUIout(tsui.ts.date) << TimeUI(tsui.ts.time, os);
}
struct TimestampUIin {
TimestampUI(Timestamp& Ts, std::ostream& qs = std::cout) :
ts(Ts), questions(qs) {}
TimestampUI(const TimestampUI&) = delete;
Timestamp& ts;
std::ostream& questions;
};
std::istream& operator>>(std::istream& is, TimestampUIin& tsui) {
DateUIin dui(tsui.ts.date, tsui.questions);
TimeUI tui(tsui.ts.time, tsui.questions);
return is >> dui >> tui;
}
//-----------------------------------------------------------------------------
int main() {
Timestamp tmp;
TimestampUI tsui(tmp, std::cout); // bind UI adapter to the Timestamp
std::vector<Timestamp> timestamps;
while(std::cin >> tsui) { // use UI adapter
timestamps.push_back(tmp); // store a raw Timestamp
}
// print collected timestamps - using adapter
for(const Timestamp& ts : timestamps) {
std::cout << TimestampUIout(ts);
}
// print collected timestamps - as they would be streamed to a file
for(const Timestamp& ts : timestamps) {
std::cout << ts;
}
}
I have an object of type piggyBank and I need to write data of this object into a file and then read it. I am aware of how to write/read to a text file but how can I overload the << operator so I can write data about the object into a file?
My code for the class here:
piggyBank.h
#include <string>
#ifndef PIGGYBANK_H
#define PIGGYBANK_H
class PiggyBank
{
private:
std::string owner;
int balance;
bool broken;
int id;
static int nrOfObjects;
public:
PiggyBank(void);
PiggyBank(std::string name);
std::string getOwnerName() const;
void setOwnerName(std::string name);
bool isBroken() ;
int getBalance(int & amount) ;
};
#endif /* PIGGYBANK_H */
piggyBank.cpp
#include "PiggyBank.h"
#include "readWrite.h"
#include <string>
#include <iostream>
using namespace std;
int PiggyBank::nrOfObjects = 0; // outside constructor
PiggyBank::getNrOfObjects(){
return nrOfObjects;
}
PiggyBank::PiggyBank(void){
{this->owner="";this->balance=0;this->broken=false;}
id = ++nrOfObjects;
}
PiggyBank::PiggyBank(std::string name, int startBalance){
{this->owner=name;this->balance=startBalance;this->broken=false;}
id = ++nrOfObjects;
}
string PiggyBank::getOwnerName() const{
return this->owner;
}
void PiggyBank::setOwnerName(string name){
this->owner = name;
}
bool PiggyBank::isBroken() {
return this->broken;
}
int PiggyBank::getBalance(int & amount) {
if(!broken){
amount = balance;
return 0;
}else{
return -1;
}
}
You want the << operator to be a friend to the class and to return ostream&.
Here is a simple example to get an idea about how it works.
friend ostream& operator << (ostream& os, const PiggyBank& obj)
{
// For example something like this
os << "Information that you want to output to the file:\n";
os << "Owner: " << obj.owner << "\n";
return os;
}
And then you can use it like this:
PiggyBack obj;
ofstream fout("file.txt");
// also check to see if the file opened correctly
if(fout.fail())
{
cout << "File failed to open\n";
return 0;
}
fout << obj;
// now you have written the owner information onto the file as well as the message before it
// inside the operator<< overload
// close the resource at the end
fout.close();
The cool part is that you can use it to print to the console too by changing fout to be cout.
For example:
cout << obj; // will print to the console
Very simple. Overload the inserter operator. Write this into your class:
friend std::ostream& operator << (std::ostream& os, const PiggyBank& pb) {
return os << pb.owner << . . . // Whatever you want
Then you can use the inserter operator as for any other data type:
int main() {
PiggyBank pb;
if (std::ofstream os("FileName"); os) {
os << pb << "\n";
}
return 0;
}
I have next c++ class called "Contact":
class Contact
{
private:
std::string contactName;
double subscriptionPrice;
int minutesIncluded;
public:
Contact(const std::string &contactName, double subscriptionPrice,
int minutesIncluded) : contactName(contactName), subscriptionPrice(subscriptionPrice), minutesIncluded(minutesIncluded)) {}
Contact() {
}
...gettetrs and setters
}
I have text file with one or more contacts in format:
asd,1.00000,1
In main method I have method that add properly vector of contacts in this text file. Problem is when I try to read from it. My target is to convert text file into vector of contacts. Method I use is next:
void phonebook_load(vector<Contact> &contacts)
{
string line;
ifstream phonebook_file;
vector<std::string> lines;
phonebook_file.open(phonebook_filename);
if(!phonebook_file.is_open())
cout << "Phonebook file could not be openned !!!" << endl;
else
{
while (phonebook_file.good())
{
for (string line; getline(phonebook_file, line, ','); )
lines.push_back(line);
}
phonebook_file.close();
}
}
I have two options:
Read line by line (which I cannot split by ",")
Split by "," which print every property of contact on new line, and I don't see how tho handle it from there.
What should I change in my method in order to read file line by line and properly convert it to vector<Contact>
Provide stream extraction and stream insertion operators for your type:
#include <string>
#include <vector>
#include <iterator>
#include <fstream>
#include <iostream>
class Contact
{
private:
std::string contactName;
double subscriptionPrice;
int minutesIncluded;
public:
Contact() {}
Contact(const std::string &contactName, double subscriptionPrice, int minutesIncluded)
: contactName { contactName },
subscriptionPrice { subscriptionPrice },
minutesIncluded { minutesIncluded }
{}
// declare the stream extraction and stream insertion operators as firends
// of your class to give them direct access to members without the need for
// getter and setter functions.
friend std::istream& operator>>(std::istream &is, Contact &contact);
friend std::ostream& operator<<(std::ostream &os, Contact const &contact);
};
std::istream& operator>>(std::istream &is, Contact &contact)
{
std::string contact_name;
if (!std::getline(is, contact_name, ',')) // use getline with a delimiter
return is; // to allow whitespace in names
// which >> doesn't
char seperator;
double subscription_price;
int minutes_included;
if (!(is >> subscription_price >> seperator >> minutes_included) || seperator != ',') {
is.setstate(std::ios::failbit);
return is;
}
contact = Contact{ contact_name, subscription_price, minutes_included };
return is;
}
std::ostream& operator<<(std::ostream &os, Contact const &contact)
{
os << contact.contactName << ", " << std::fixed << contact.subscriptionPrice
<< ", " << contact.minutesIncluded;
return os;
}
int main()
{
std::ifstream is{ "test.txt" };
std::vector<Contact> contacts{ std::istream_iterator<Contact>{ is },
std::istream_iterator<Contact>{} };
for (auto const &c : contacts)
std::cout << c << '\n';
}