Writing to an array class will not cout - c++

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

Related

How can I read data from a file into a vector of class without using getLine()?

I have some data in the file that I would like to be able to read into a vector of a class-type/object. This object also has within itself a vector that takes in another class type, and the data that needs to populate that inner vector is also contained within the text file. How can I read the data from the file into the vectors accordingly without using getLine()?
The data is formatted as so in the document.
143 Jones
1234 2 C
-1
123 Smith
4321 4 A
132 3 B
-1
Where the first line is the ID of the student followed by their name, and below it is a series of classes that student has taken followed by the number of credits each course is worth and the grade the student got for the course.
Below is the course class header code
#pragma once
#include <iostream>
class Course {
public:
Course(int, int, std::string);
int getCourseCode() const {return courseCode;}
int getCredits() const {return courseCredits;}
std::string getGrade() const {return grade;}
void print(std::ostream &os) const;
private:
int courseCode;
int courseCredits;
std::string grade;
};
inline std::ostream &operator <<(std::ostream &os, const Course &course) {
course.print(os);
return os;
}
inline Course::Course(int courseCode, int courseCredits, std::string grade) {
this->courseCode = courseCode;
this->courseCredits = courseCredits;
this->grade = grade;
}
Below is the student class header code
#pragma once
#include <vector>
#include "course.h"
class Student {
public:
Student(int, std::string, std::vector<Course> courses);
int getID() const;
double getGPA() const;
std::string getName() const;
void print(std::ostream &os) const;
std::vector<Course> courses;
private:
int id;
std::string name;
};
inline std::ostream &operator << (std::ostream &os, const Student &student) {
student.print(os);
return os;
}
Below is the student.cpp code
#include "student.h"
#include <string>
using namespace std;
Student::Student(int id, std::string name, vector<Course> courses) {
this->id = id;
this->name = name;
this->courses = courses;
}
int Student::getID() const {
return id;
}
string Student::getName() const {
return name;
}
double Student::getGPA() const {
double total;
double creds;
double cgrade;
double gpa;
for(int i = 0; i < courses.size(); i++) {
if(courses[i].getGrade() == "A") cgrade = 4.0;
else if(courses[i].getGrade() == "B") cgrade = 3.0;
else if(courses[i].getGrade() == "C") cgrade = 2.0;
else if(courses[i].getGrade() == "D")cgrade = 1.0;
total += cgrade * courses[i].getCredits();
creds += courses[i].getCredits();
}
gpa = total / creds;
return gpa;
}
void Student::print(std::ostream &os) const {
os << id << " " << name << ": " << this->getGPA() << endl;
for(int i = 0; i < courses.size(); i++) {
os << courses[i];
}
}
This is what I've tried so far in terms of trying to load the vectors
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "student.h"
using namespace std;
void loadStudents(string fileName, vector<Student> &students);
bool compareCourses(const Course &c1, const Course &c2);
bool compareStudents(const Student &s1, const Student &s2);
void printResults(string fileName, vector<Student> &students);
int main() {
try {
vector<Student> students;
loadStudents("students.data", students);
cout << students.size() << " records processed" << endl;
return 0;
}
catch(string message) {
cout << "Error: " << message << endl;
exit(1);
}
};
void loadStudents(string fileName, vector<Student> &students) {
ifstream studentsFile(fileName.c_str());
if(!studentsFile.good()) {
throw string("Input file: " + fileName + ", not found!");
}
int id;
string name;
vector<Course> cs;
while(studentsFile >> id >> name >> cs) {
students.place_back(student);
}
studentsFile.close();
}
bool compareCourses(const Course &c1, const Course &c2) {
return c1.getGrade() < c2.getGrade();
}
bool compareStudents(const Student &s1, const Student &s2) {
return s1.getGPA() < s2.getGPA();
}
void printResults(string fileName, vector<Student> &students) {
ofstream outputFile(fileName.c_str());
if(!outputFile.good()) {
throw string("Output file: " + fileName + ", not found!");
}
for(auto student : students) {
outputFile << student.print(outputFile) << endl;
}
outputFile.close();
}
I'm getting an error stating that "no operator ">>" matches these operands" in the while loop inside the loadStudents function, which I think pertains to the istream for the vector.
The desired output is something like this printed to an output file.
143 Smith: 3.57143
4321 (4 credits): A
132 (3 credits): B
143 Jones: 2
1234 (2 credits): C
2 records processed
Where the student ID and name are printed along with their calculated GPA and the courses they took below them followed by a message stating the number of students that were processed.
My main issue pertains to the loading of the students vector with the subsequent data of the course information being appropriately loaded into the courses vector for each student. Is this possible without using the getLine() method and istream >>?

OOP Vector edit issue

I have created a function that should edit the attributes of a class stored in a database. However, the vector insert function doesn't work as I expected. Could someone please suggest how I should implement the insert vector function to fill the hole I have made?
Whenever I implement it, this pops up:
Process finished with exit code -1073741819 (0xC0000005)
Code:
using namespace std;
int Natobase::counter = 0;
Natobase::Natobase(string n, string ci, string co, int ri, int tan, int pla, int lan)
: name(n), city(ci), country(co), rifles(ri), tanks(tan), planes(pla), launcher(lan) {};
Natobase::Natobase(string init) : Natobase("20thDiv", "Kuldiga", "Latvia", 100, 50, 75, 32) {};
std::ostream &printnames(std::ostream &pr, Natobase &pro) {
pr << "\nID:" << pro.ID << "\nName:" << pro.name;
return pr;
}
std::istream &operator>>(std::istream &re, Natobase &product) {
std::cout << "Enter the name of the base: \n";
re >> product.name;
std::cout << "Enter the city where it is located: \n";
re >> product.city;
std::cout << "Enter the country where it is located: \n";
re >> product.country;
std::cout << "Enter the number of guns held: \n";
re >> product.rifles;
std::cout << "Enter the number of tanks stationing: \n";
re >> product.tanks;
std::cout << "Enter the number of planes stationing: \n";
re >> product.planes;
std::cout << "Enter the number of launchers stationing: \n";
re >> product.launcher;
product.get_counter();
product.ID = product.counter;
return re;
}
**void Database::EditDB() {
Natobase nato;
int editt;
cout << "Enter the number of the base that you want to change:\n";
std::cout << "The bases are:\n";
printids();
cin >> editt;
auto iter = std::find_if(std::begin(DbMain), std::end(DbMain), [&](Natobase& nb)
{ return nb.get_ID() == editt; });
if (iter != DbMain.end())
{
DbMain.erase(iter);
cout << "\nPlease enter the input of the base one more time" << endl;
cin >> nato;
DbMain.insert(DbMain.begin() + iter->get_ID(), nato);
cout << "\nSuccess";
}
}**
Header file included:
//
// Created by Stasd on 28/04/2022.
//
//Stanislaw Dutkiewicz 263509
#ifndef OOPLABPROJECT_NATOBASE_H
#define OOPLABPROJECT_NATOBASE_H
#include <string>
#include <vector>
#include "Natobase.h"
class Natobase {
friend std::ostream &tosave(std::ostream &, const Natobase &);
friend std::istream &toim(std::istream &, Natobase &);
friend std::ostream &printnames(std::ostream &, Natobase &);
friend std::istream &operator>>(std::istream &, Natobase &);
public:
Natobase() = default;
Natobase(std::string n, std::string ci, std::string co, int ri, int tan, int pla, int lan); //read-only
Natobase(std::string init); //initialisation
const std::string &get_name() const { return this->name; }
const std::string &get_city() const { return this->city; }
const std::string &get_country() const { return this->country; }
const int &get_rifle() const { return this->rifles; }
const int &get_tanks() const { return this->tanks; }
const int &get_planes() const { return this->planes; }
const int &get_launch() const { return this->launcher; }
const int &get_ID() const { return this->ID; }
friend class Database;
private:
std::string name;
std::string city;
std::string country;
int rifles;
int tanks;
int planes;
int launcher;
static int counter;
int ID;
static int get_counter()
{
counter++;
return counter;
};
};
std::ostream &tosave(std::ostream &, const Natobase &); //save data into txt file
std::istream &toim(std::istream &, Natobase &);// to read the data from txt file
std::ostream &printnames(std::ostream &, Natobase &); //used for edit and remove function in Database class
std::ostream &operator<<(std::ostream &, const Natobase &); //input attributes
std::istream &operator>>(std::istream &, Natobase &); //output attributes
/////////////////////////
////////////////////////
class Database {
public:
Database() = default;
void print_data();
void read_data();
void saveDB();
void openDB();
void EditDB();
void RemoveDB();
void printids();
void compare();
private:
std::vector<Natobase> DbMain;
};
#endif //OOPLABPROJECT_NATOBASE_H
From this erase reference:
Invalidates iterators and references at or after the point of the erase, including the end() iterator.
After you called erase the iterator iter is no longer valid, it can't be used anymore.
If you need to use data from it you need to copy it first before you call erase.
You also need to use the iterator that erasereturns if you want to continue your loop.

How can I overload the << operator so I can write the data of an object to a file?

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;
}

C++ read line to class vector

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';
}

Using push_back for vector in c++

I am having trouble using push_back for vectors in c++.
My vector is named data.
In my loop I want to add 50 to data[i].getQuantity then push_back to data
These are things that I have tried.
data.push_back(data[i].getQuantity());
and
float myFloat = data[i].getQuantity() + 50;
data.push_back(data[i].getQuantity(myFloat));
data.push_back(myFloat);
The error is saying
No function to call to push_back
Here is my code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
struct Input
{
friend std::istream& operator >>(std::istream& inp, Input& item);
friend std::ostream& operator <<(std::ostream& outp, Input const& item);
std::string group;
std::string total_pay;
float quantity;
// default constructor. sets up zero-elements
Input() : group(), total_pay(), quantity()
{
}
Input(std::string groupIn, std::string total_payIn, float quantityIn) :
group(std::move(groupIn)),
total_pay(total_payIn),
quantity(quantityIn)
{
}
// Accessors
std::string const& getGroup() const { return group; }
std::string getTotalPay() const { return total_pay; }
float getQuantity() const { return quantity; }
};
// global free function for extracting an Input item from an input stream
std::istream& operator >>(std::istream& inp, Input& item)
{
return (inp >> item.group >> item.total_pay >> item.quantity);
}
// global operator for inserting to a stream
std::ostream& operator <<(std::ostream& outp, Input const& item)
{
outp
<< item.getGroup() << ", "
<< item.getTotalPay() << ", "
<< item.getQuantity();
return outp;
}
struct ctype : std::ctype<char>
{
static mask* make_table()
{
static std::vector<mask> table(classic_table(),
classic_table() + table_size);
table[','] |= space;
return &table[0];
}
ctype() : std::ctype<char>(make_table()) { }
};
int main() {
std::fstream infile("employee.dat");
std::vector<Input> data;
std::string line;
try {
while (std::getline(infile, line))
{
std::istringstream iss(line);
Input inp;
iss.imbue(std::locale(iss.getloc(), new ctype));
while (iss >> inp) // calls our extraction operator >>
data.push_back(inp);
if (iss.fail() && !iss.eof())
std::cerr << "Invalid input line: " << line << '\n';
}
// dump all of them to stdout. calls our insertion operator <<
std::copy(data.begin(), data.end(),
std::ostream_iterator<Input>(std::cout,"\n"));
std::ofstream outp("output.dat");
for(int i = 0; i < data[i].getQuantity(); i++)
{
float myFloat = data[i].getQuantity() + 50;
data.push_back(myFloat);
outp << data[i].getGroup() << ',' << data[i].getTotalPay() << ',' << data[i].getQuantity() + 50 << '\n';
}
} catch (std::exception& e) {
std::cout << "There was an error: " << '\n';
return 1;
}
return 0;
}
Your vector is of type std::vector<Input>. That means you can only put objects of type Input into it. You can't push_back a float into such a vector.
If your intention is to create a new Input object and push that back into your vector, you could do something like
data.push_back(Input(data[i].getGroup(), data[i].getTotalPay(), data[i].getQuantity() + 50))
On the other hand, if you are simply trying to modify an element in data without adding a new element to data, you could just do
data[i].quantity += 50;
This works because you use a struct rather than a class. In a struct, variables default privacy level is public. If you wanted to use a class, or you just don't want to directly access the struct members, you would have to create a setter function for quantity.