Reading a file into a vector of class objects - c++

I have given it a few tries based on what I've read on numerous forums and books I have here. More details about this assignment here with more code from it: Click- another question from StackOverflow
What exactly I need to do is create a file with CHotel objects and insert them in this vector m_hoteli.
As to why it isn't working, it is either not reading the string from the file and it's not filling the vector at all.
This is my file:
"Marina" 5 500
"Tulip" 4 400
"BlackSea" 3 300
"SwissBell" 5 600
class CComplex:CHotel
{
protected:
string m_complex;
vector<CHotel> m_hoteli;
public:
CComplex(){};
CComplex(string filename, string nComplex)
{
fstream file("filename.txt", ios::in);
CHotel temp(" ",0,0);
while (file >> temp)
{
m_hoteli.push_back(temp);
}
/* Second try:
m_complex = nComplex;
fstream in;
in.open(filename, ios::in);
string s;
while (getline(in, s))
{
CHotel h1(s);
m_hoteli.push_back(h1);
}
Third try:
m_complex = nComplex;
ifstream iStream(filename);
if (iStream.good())
{
copy(istream_iterator<CHotel>(iStream), istream_iterator<CHotel>(), back_inserter(m_hoteli));
}
}
*/
}
That's the CHotel code:
class CHotel : public CTurist
{
protected:
string hName;
int stars;
int beds;
map<CTurist, unsigned> Turisti;
public:
unsigned Sum = 0;
int br = 0;
CHotel(){};
CHotel(string hName2, int zvezdi, int legla)
{
hName = hName;
stars = zvezdi;
beds = legla;
}
friend istream& operator>>(std::istream& is, CHotel& e)
{
is >> e.hName >> e.stars >> e.beds;;
return is;
}
I just do this in the main: CComplex c1("filename.txt", "Complex1");

You are not using the filename parameter in the CComplex constructor, other than that your code should work.
fstream file(filename, ios::in);
Do you know how to step debug? Here is some info on debugging
Here is your full code, the only change is the filename parameter and the file should now be placed in c:\temp.
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <fstream>
using namespace std;
class CTurist
{
protected:
string tName;
int age;
public:
CTurist() {};
CTurist(string name, int age2)
{
tName = name;
age = age2;
}
bool operator<(const CTurist& e) const
{
return age < e.age;
}
friend ostream& operator<<(ostream& os, const CTurist&& e);
friend ifstream& operator>>(ifstream& is, CTurist&& e);
};
class CHotel : public CTurist
{
protected:
string hName;
int stars;
int beds;
map<CTurist, unsigned> Turisti;
public:
unsigned Sum = 0;
int br = 0;
CHotel() {};
CHotel(string hName2, int zvezdi, int legla)
{
hName = hName;
stars = zvezdi;
beds = legla;
}
friend istream& operator>>(std::istream& is, CHotel& e)
{
is >> e.hName >> e.stars >> e.beds;;
return is;
}
};
class CComplex :CHotel
{
protected:
string m_complex;
vector<CHotel> m_hoteli;
public:
CComplex() {};
CComplex(string filename, string nComplex)
{
fstream file(filename, ios::in);
CHotel temp(" ", 0, 0);
while (file >> temp)
{
m_hoteli.push_back(temp);
}
}
};
int main()
{
CComplex c1("C:\\temp\\file.txt", "Complex1");
system("pause");
return 0;
}
Try putting a breakpoint in main and step through your program with f11 and f10

Related

Reading input from command line, separated by whitespace, into array of objects

I am experimenting with reading input from command line and successfully store them in objects attributes.
Example of input (./(nameOfExecutable) < (sourceText) in the command line)
20 5
1 5
28 5
2 5
20 5
4 5
22 5
88 3
27 5
34 5
I want to read and store them into object attributes.
experimentClass.h
#ifndef EXPERIMENTCLASS_H
#define EXPERIMENTCLASS_H
#pragma once
class experimentClass
{
public:
experimentClass(int x, int y);
~experimentClass();
private:
int age;
int favoriteNumber;
};
#endif
experimentClass.cpp
#include "experimentClass.h"
experimentClass::experimentClass(int x, int y)
{
age = x;
favoriteNumber = y;
}
experimentClass::~experimentClass()
{
}
main.cpp
#include <iostream>
#include "experimentClass.h"
using namespace std;
int main(){
int age;
int favoriteNumber;
std::cin >> age;
std::cin >> favoriteNumber;
experimentClass a(age, favoriteNumber);
}
In this case, I am able to store 20 into a's age, 5 into a's favoriteNumber.
However, I want to do this process until it hits the end of input.
So, in this case, I want to create 10 objects with given input, using iteration, and store these object into an array or something.
How can I read them properly so that I can achieve this?
Simply take the logic you already have and put it inside a loop, eg:
#include <iostream>
#include <vector>
#include "experimentClass.h"
using namespace std;
int main() {
int age;
int favoriteNumber;
vector<experimentClass> vec;
while (cin >> age >> favoriteNumber) {
experimentClass a(age, favoriteNumber);
vec.push_back(a);
}
// use vec as needed...
}
Then you can take this a step further by implementing an operator>> for your class, eg:
#ifndef EXPERIMENTCLASS_H
#define EXPERIMENTCLASS_H
#include <istream>
#pragma once
class experimentClass
{
public:
experimentClass(int x = 0, int y = 0);
friend std::istream& operator>>(std::istream &is, experimentClass &cls);
private:
int age;
int favoriteNumber;
};
std::istream& operator>>(std::istream &is, experimentClass &cls);
#endif
#include "experimentClass.h"
experimentClass::experimentClass(int x, int y)
{
age = x;
favoriteNumber = y;
}
std::istream& operator>>(std::istream &is, experimentClass &cls)
{
return is >> cls.age >> cls.favoriteNumber;
}
#include <iostream>
#include <vector>
#include "experimentClass.h"
using namespace std;
int main() {
experimentClass a;
vector<experimentClass> vec;
while (cin >> a) {
vec.push_back(a);
}
// use vec as needed...
}
You could model the input line with a struct:
struct Record
{
unsigned int m_age;
int m_favorite_number;
};
Then overload the operator>>:
struct Record
{
unsigned int m_age;
int m_favorite_number;
friend std::istream& operator>>(std::istream& input, Record& r);
};
std::istream& operator>>(std::istream& input, Record& r)
{
input >> r.m_age;
input >> r.m_favorite_number;
return input;
}
You could read in the data into a database by using:
std::vector<Record> database;
Record r;
while (std::cin >> r)
{
database.push_back(r);
}
In the above call, you could replace std::cin with a file stream.
You could print or display a record from the database:
std::cout << database[3].m_age << " " << database[3].m_favorite_number << "\n";
Although IMHO, you should overload operator<< to print the record in a default format.
Since you are using nameOfExecutable.exe < source.txt, you can use cin.eof to check if the end of file is reached:
while(true){
int a, b;
std::cin >> a;
if(std::cin.eof()){
break;
}
std::cin >> b;
//Create Class
}

Trying to read two files in the same time

I am playing with threads but I don't know why this code doesn't work properly. It has to read two files(the names of the files come from keyboard) and then show the contents in the console. Could you tell me where is the problem?
#include<iostream>
#include<fstream>
#include<thread>
#include<string>
#include<vector>
using namespace std;
mutex mtx;
class eu
{
string filename;
string buffer;
public:
eu() {};
void citire(string filename)
{
this->filename = filename;
ifstream f(filename);
while (f.eof())
{
string ceva;
f >> ceva;
buffer = buffer + ceva;
}
f.close();
}
/*void operator()() it doesn't work either in this way
{
this->citire(filename);
}*/
friend ostream &operator<<(ostream& os, eu&n);
//~eu();
};
ostream& operator<<(ostream& os, eu&n)
{
os << n.buffer;
return os;
}
//threads.push_back(std::thread(&C::increase_member,std::ref(bar),1000));
int main()
{
vector<thread>instante;
string nume;
eu n;
for (int i = 0; i <2; i++)
{
cin >> nume;
instante.push_back(thread(&eu::citire, n, nume));
}
for (auto& th : instante) th.join();
cout << n;
}

After writing binary file and reading a record (an object) from the binary file, enum type last attribute of the record is NULL ( default value)

I'm trying to write a C++ code that read from a text file, write all the contents into a binary file, and read a record from the binary file.To hold records, I created a Student class that one of its attribute is enum type.I read from text file successfully, I write the Student records successfully (I check it while debugging), but I have a problem with reading one Nth record from the binary file.Although all attribute are taken successfully, the last attribute whic is enum type is not changed and seems as default even for all records.Although no error exists in the VS 2017, with debugging I recognize that the problem is at binaryRead and readRecord parts (The data in "this" shows the enum attribute as NONE.Also sizeOfOneStudentRecord in seekg, read, readRecord, binaryRead etc. can be not true. I need help friends.
The code is given below. I will aprreciate your help.
enum Category { NONE = 0, Honor=1, High_Honor = 2 };
class Student
{
private:
string name;
double weight;
int age;
Category degree;
public:
Student();
Student(string _name, double _weight, int _age, Category _degree);
Student* txtRead(ifstream& myFile);
size_t sizeOfOneStudentRecord(Student* a);
void binaryWrite(fstream& myFile);
void binaryRead(fstream& myFile);
void readRecord(fstream& binmyFile, int order);
friend ostream& operator<<(ostream& output, Student& s) {
..
}
};
Student::Student()
{
name = "";
weight = 0.0;
age = 0;
degree = NONE;
}
Student::Student(string _name, double _weight, int _age, Category _degree)
{
name = _name;
weight = _weight;
age = _age;
degree = _degree;
}
size_t Student::sizeOfOneStudentRecord(Student* c) {
return sizeof(this->name) + sizeof(this->weight) + sizeof(this->age) + sizeof(this->degree);
}
Student* Student::txtRead(ifstream& myFile) {
...
}
void Student::binaryWrite(fstream& myFile) {
myFile.write((char *)this, sizeOfOneStudentRecord(this));
}
void Student::binaryRead(fstream& myFile) {
myFile.read((char*)this, sizeOfOneStudentRecord(this));
}
void Student::readRecord(fstream& binmyFile, int order) {
binmyFile.seekg((order)*sizeOfOneStudentRecord(this));
binaryRead(binmyFile);
name = this->name;
age = this->age;
weight = this->weight;
degree = this->degree;
}
int main() {
Student *StudentArr[20];
ifstream myFile("Student.txt", ios::in);
ofstream txtmyFile("newStudentFile.txt", ios::out | ios::trunc);
fstream binmyFile("StudentBin.bin", ios::out | ios::in | ios::trunc | ios::binary);
for (int i = 0; i < 20; i++) {
StudentArr[i] = new Student();
StudentArr[i]->txtRead(myFile);
txtmyFile << *StudentArr[i];
StudentArr[i]->binaryWrite(binmyFile);
}
myFile.close();
txtmyFile.close();
Student s1;
s1.readRecord(binmyFile, 8);
std::cout << s1 << endl;
binmyFile.close();
return 0;}

create objects based on entries from a file

How to create objects during runtime based on input from file.
I have few entries in a file in an organized way separated by a space
entryname type satus
entry1 type1 yes
entry2 type2 no
...
I would like to create objects of below class based on number of entries.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
class Entry{
std::string name;
std::string type;
std::string availability;
};
void getEntriesInfo(std::vector<std::string> &info)
{
std::string line;
std::fstream myfile("entries.txt",std::ios::in);
if (myfile.is_open())
{
//remove first line from file.
getline(myfile,line);
while ( getline(myfile,line) )
info.push_back(line);
myfile.close();
}
else std::cout << "Unable to open file";
}
int main()
{
std::vector<std::string> entries_info;
getEntriesInfo(entries_info);
for(auto &e: entries_info)
std::cout<<e<<std::endl;
return 0;
}
EDIT 1:
I have restructured code a bit using maps and vectors, can it be made more elegant.
If you look at the code , I have not used constructors & destructors properly, (I could not figure out a good way to use), also the setters and not written all kinds of constructors(deep copy or move) etc..
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
//#include <istream>
#include <map>
class AItem;
AItem makeItem(std::string );
void displayItemInfo(std::vector<std::string> info);
class Item {
public:
virtual ~Item() = default;
virtual std::string name() const = 0 ;
virtual std::string quota() const = 0 ;
virtual std::string make() const = 0 ;
};
class AItem : Item{
private:
std:: string _name;
std:: string _quota;
std:: string _make;
public:
virtual std::string name() const { return _name;}
virtual std::string quota() const { return _quota;}
virtual std::string make() const {return _make;}
void setName();
void setQuota();
void setMake();
AItem(){}
AItem(std::string name,std::string quota,std::string make) :_name(name),_quota(quota),_make(make) {}
friend std::istream& operator>>(std::istream& in,AItem& item);
friend std::ostream & operator << (std::ostream &out, const AItem & item);
};
void displayItemInfo(std::vector<std::string> info)
{
for(auto &i_it:info)
std::cout<<i_it<<std::endl;
}
std::vector<std::string> readItemInfo(const char *str)
{
std::string line;
std::vector<std::string> itemInfo;
std::ifstream file(str, std::ios::in);
if(file.is_open()){
getline(file,line);
while(getline(file,line))
itemInfo.push_back(line);
file.close();
}else{
std::cout<<"Unable to open"<<str<<std::endl;
}
return itemInfo;
}
std::ostream &operator << (std::ostream &out,const AItem& item)
{
//std::cout <<item.name()<<" "<<item.quota()<<" "<<item.make() <<std::endl;
return out <<item.name()<<" "<<item.quota()<<" "<<item.make() <<std::endl;
}
std::istream& operator >> (std::istream& in,AItem& item) {
//in >> item._name >> item._quota >> item._make;
return in >> item._name >> item._quota >> item._make;
}
AItem makeItem(std::string aitem)
{
std::stringstream ss(aitem);
std::vector<std::string> arguments;
std::string entry;
while (ss >> entry) {
arguments.push_back(entry);
}
AItem aItem_obj(arguments.at(0),arguments.at(1),arguments.at(2));
return aItem_obj;
}
std::map<std::string,AItem> createItems(std::vector<std::string> item)
{
std::map<std::string,AItem> ItemMap;
for(auto &i_it:item) {
AItem a_item = makeItem(i_it);
ItemMap.insert(std::make_pair(a_item.name(),a_item));
}
// for(auto &m:ItemMap)
// std::cout<<m.first<<m.second<<std::endl;
return ItemMap;
}
int main(int argc, char*argv[])
{
char *str = "player_info.txt";
std::vector<std::string> info;
std::map<std::string,AItem> ItemMap;
// info = readItemInfo(str);
// displayItemInfo(info);
//#if 0
ItemMap = createItems(readItemInfo(str));
for(auto &item:ItemMap)
std::cout<<item.first<<item.second<<std::endl;
//#endif
return 0;
}
EDIT 2
I have done this way
entry.h
#include <iostream>
#include <string>
class Entry{
private:
std::string name;
std::string type;
std::string availability;
public:
std::string getName(void) const;
std::string getType(void) const;
std::string getAvailability(void) const;
void setName(const std::string n);
void setType(const std::string t);
void setAvailability(const std::string y);
Entry();
~Entry();
friend std::ostream &operator << (std::ostream &out,const Entry &e);
};
entry.cpp
#include "entry.h"
std::string Entry ::getName(void) const{
return name;
}
std::string Entry ::getType(void) const{
return type;
}
std::string Entry ::getAvailability(void) const{
return availability;
}
void Entry ::setName(const std::string n){
name = n;
}
void Entry ::setType(const std::string t){
type = t;
}
void Entry ::setAvailability(const std::string y){
availability = y;
}
Entry::Entry(){
}
Entry::~Entry(){
}
std::ostream &operator << (std::ostream &out,const Entry &e){
return out << e.getName()<<" " <<e.getType()<<" "<<e.getAvailability()<<std::endl;
}
main.cpp
#include <fstream>
#include <vector>
#include "entry.h"
void makeEntry(std::string line,std::vector<Entry> &entries)
{
Entry P1;
P1.setName(line.substr(0, line.find(' ')));
P1.setType(line.substr(P1.getName().size(), line.find(' ')));
P1.setAvailability(line.substr(P1.getName().size()+P1.getType().size(), line.find(' ')));
//std::cout<<"C:"<<P1.getName()<<P1.getType()<<P1.getAvailability()<<std::endl;
entries.push_back(P1);
}
void getEntriesInfo(std::vector<std::string> &info)
{
std::string line;
std::fstream myfile("entries.txt",std::ios::in);
if (myfile.is_open())
{
//remove first line from file.
getline(myfile,line);
while ( getline(myfile,line) )
info.push_back(line);
myfile.close();
}
else std::cout << "Unable to open file";
}
int main()
{
std::vector<std::string> entries_info;
std::vector<Entry> entries;
getEntriesInfo(entries_info);
for(auto &e: entries_info) {
std::cout<<e<<std::endl;
makeEntry(e,entries);
}
std::cout<<"OUT"<<std::endl;
for(auto &e: entries) {
std::cout<<e<<std::endl;
}
return 0;
}
You can provide an overload for the stream extraction operator:
std::istream& operator>>(std::istream& in,Entry& e) {
in >> e.name >> e.type >> e.availability;
}
This works, when the individual entries in the file do not contain spaces. Ie it would fail for
entryName LastName type1 yes
In this case you would need to have a seperator (eg ;) and use std::getline to parse the lines.
Reading entries into a vector is then (assuming you know the number of entries beforehand):
std::vector<Entry> readFromFile(std::istream& myfile,size_t n_entries) {
std::vector<Entry> entries;
data.resize( n_entries );
for (auto& e : entries ) myfile >> e;
return entries;
}

usage of istream in class constructor c++

I have a text file that contains a list of students and their marks and looks like this:
Name_of_student 78 4; 98 5; 90 5; 63 3;
...
I have an assignment to create a class that will read and store that data. This is what I've done so far.
group.h
class Subject {
public:
Subject(int mark0, int mark1);
Subject();
int get_m0() { return mark0; }
int get_m1() { return mark1; }
private:
int mark0;
int mark1;
};
class Student {
public:
Student(string name);
Student();
vector<Subject>my_marks;
string get_name() { return name; }
private:
string name;
};
class Reading
{
public:
Reading(vector<Student>, istream& );
istream& read_student();
private:
vector<Student>group;
istream& is;
};
text.cpp
Subject::Subject(int m0, int m1) :
mark0(m0), mark1(m1) {}
Subject::Subject() :
mark0(1), mark1(1) {}
Student::Student(string n0) :
name(n0) {}
Student::Student() :
name("null") {}
Reading::Reading(vector<Student>group0, istream& is0) :
group(group0), is(is0) {}
istream& Reading::read_student()
{
string n;
is >> n;
if (!is) return is;
Student st = Student(n);
for (int i = 0; i < 4; ++i)
{
int m0, m1;
is >> m0 >> m1;
char ch;
is >> ch;
Subject sub = Subject(m0, m1);
st.my_marks.push_back(sub);
}
group.push_back(st);
return is;
}
It compiles, but refuses to read anything.
int main()
{
ifstream ifs("text");
if(!ifs) error("can`t open input file");
vector<Student> group;
Readding r(group, ifs);
r.read_student();
cout << group.size();
}
And what it shows:
0
If anyone has any ideas I'd appreciate it.
In Reading::read_student(), you are filling up the member variable Reading::group. You are not filling up the function variable group in main.
Use:
int main()
{
ifstream ifs("text");
vector<Student> group;
Readding r(group, ifs);
r.read_student();
cout << r.group.size();
// ^^^^^^^^ access the member variable of r.
}
If you want the function variable group to be filled up, Reading needs to store a reference to the input group.
class Reading
{
public:
Reading(vector<Student> & , istream& );
// ^^^^^^ Take a reference as input
istream& read_student();
private:
vector<Student>& group;
// ^^^^^^ store a reference
istream& is;
};
What i have changed:
group.h
class Reading
{
public:
Reading( istream& );
vector<Student>group;
istream& read_student();
private:
istream& is;
};
text.cpp
Reading::Reading(istream& is0) :
is(is0) {}
int main()
{
ifstream ifs("text");
if(!ifs) error("can`t open input file");
Readding r(ifs);
r.read_student();
cout << r.group.size();
}
And now it works all correct!!!