I have encountered a roadblock with a member function that is supposed to read from a file and append content, line by line, to an array of Player objects. Originally I was passing the testList2 object into the member function by reference and the code was working fine, but I have been informed that the main file can not be altered and that the readFile function can only take one parameter. Below is a snippet of code from a test file, and the aformentioned readFile member function.
I want to figure this out, so if anyone has some general advice to point me in the right direction without giving the answer, I would be greatful.
Contestants testList2;
std::cout << "-----BEGIN FILE I/O TEST -----------\n\n";
std::cout << "Test 1 - error opening file\n";
std::cout << "\tEXPECTING: Could not open file.\n";
std::cout << "\tACTUAL: ";
testList2.readFile("testFil");
std::cout << "\nTest 2 - append to object from file\n";
testList2.readFile("testFile2"); // Function call here. Can not add second parameter.
std::cout << "\nPrinting testList2 contents\n";
for(int i = 0; i < testList2.getSize(); i++) {
std::cout << "Player " << i + 1 << "\n";
std::cout << testList2.at(i) << std::endl;
}
bool Contestants::readFile(std::string fileName) {
// Create object and open file
Player tmpPlayer;
std::ifstream inFile(fileName);
// Check that file is open.
if(!inFile) {
std::cout << "Could not open file." << std::endl;
return false;
}
std::cout << "File opened.\n" << std::endl;
// Read the file line by line
std::string line;
std::string tmpName;
std::string tmpScore;
while(std::getline(inFile, line)) {
//std::cout << line << std::endl; // This line is for testing purposes
// Create a string stream read from input file.
std::stringstream ss(line);
// Store contents of the file into two seperate value delimited by a comma.
if(std::getline(ss, tmpName, ',')) {
if(std::getline(ss, tmpScore)) {
tmpPlayer = Player(tmpName, stoi(tmpScore));
testList2.append(tmpPlayer); // HOW TO APPEND TO CONTESTANTS OBJECT WITHOUT A SECOND FUNCTION PARAMETER?
}
}
}
// Check for errors or end of file
if (inFile.bad()) {
std::cout << "Error reading file." << std::endl;
return false;
} else if (inFile.eof()) {
std::cout << "\nEnd of file reached." << std::endl;
}
// Close the file.
inFile.close();
std::cout << "\nFile closed." << std::endl;
return true;
}
class Contestants
{
public:
// Static constant size maximum for array size.
static const int MAX_SIZE = 3;
// Default constructor
Contestants();
// Capacity
int getSize() const; // Returns the number of objects held within Contestants
int getMaxSize() const; // Returns the value of MAX_SIZE
bool isEmpty() const; // Checks for empty object array.
// Accessors
int contains(const Player& player) const; // Determines if Contestants contains specified Player object
const Player& at(int index) const; // Returns player object found at index param
const Player& operator[](int index) const; // TODO
// Modifiers
void clearAll(); // Resets object array to 0.
bool append(const Player& player); // Adds player objects and increases size.
bool removePlayer(const Player& player); // Finds player object and calls removeByIndex()
bool removeByIndex(int index); // removes specified player object
// Other (file IO)
bool readFile(std::string fileName); // TODO
bool writeFile(std::string fileName); // TODO
private:
Player data[MAX_SIZE];
int size;
};
I have tried various pointer methods but all throw errors.
I want to figure this out, so if anyone has some general advice to point me in the right direction without giving the answer...
I will try NOT to give an answer :)
Your readFile() function is a member on your class Contestants, so you do not have to "pass testList2 object into the member function"
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 23 days ago.
Improve this question
Recently I've started working on my first OOP project and after having written the program I am trying to optimize it for code efficiency. I want to place the parts of the program that are being copied a lot on the heap.
I can't understand why in certain places objects are copied.
An example:
In the main.cpp movies object, which stories movie objects, is created. Add_movie function is called that checks if the movie we are trying to add has already been added, if not, we create a temp object, initialize its private members to the argument values being passed, append it to the vector of the movies object. A copy constructor would be called when movie object is being appended to the vector. WHY? I can't understand the part WHY is it being copied? Is it because of the scope???
If there was an object initialized in the main like
Movie movie1{arguments};
and other movie is created based on movie1
Movie movie2{movie1}.
It makes sense to me, but in the example I gave, it doesn't make sense to me at all
The example of the function I am referring to
bool Movies::add_movie(std::string name, std::string rating, int watched)
{
for (const Movie& obj : movies_list)
{
if (obj.get_name() == name) // search for a match
{
return false; // if found stop executing
}
}
Movie temp{ name, rating, watched }; // creates a new object and initializes its private members to the passed arguments
# movies_list.push_back(temp); // appends the object to the vector
# *** return true;
}
I don't know if it will help, but there is the code of the program
**main.cpp **
#include "Movie.h"
#include "Movies.h"
#include <iostream>
#include <string>
void add_movie(Movies& obj, std::string name, std::string rating, int watched)
{
if (obj.add_movie(name, rating, watched))
{
std::cout << name << " succesfully added" << std::endl;
}
else
{
std::cout << name << " already has been added" << std::endl;
}
}
// if the parent increment_watched function returns true, inform the user about the result of the operation
void increment_watched(Movies &obj, std::string name)
{
if (obj.increment_watched(name)) // if Movies::increment_watched returns
{
std::cout << name << " watch count succesfully incremented by 1" << std::endl;
}
else {
std::cout << name << " movie not found" << std::endl;
}
}
int main()
{
Movies list;
add_movie(list, "Fight Club", "A", 1);
add_movie(list, "Fight Club", "A", 1);
add_movie(list, "Inception", "A", 1);
increment_watched(list, "Fight Club");
increment_watched(list, "Else Test");
list.display();
return 0;
}
movies.cpp
#include "Movie.h"
#include "Movies.h"
#include <iostream>
bool Movies::add_movie(std::string name, std::string rating, int watched)
{
for (const Movie& obj : movies_list)
{
if (obj.get_name() == name) // search for a match
{
return false; // if found stop executing
}
}
Movie temp{ name, rating, watched }; // creates a new object and initializes its private members to the passed arguments
movies_list.push_back(temp); // appends the object to the vector
return true;
}
void Movies::display() const
{
if (movies_list.size() == 0) // checks the vector size
{
std::cout << "The list is empty" << std::endl;
}
else
{
std::cout << "\nThe list of the movies: " << std::endl;
std::cout << "----------------------------" << std::endl;
for (const Movie& obj : movies_list)
{
obj.display_members(); // accesses the private members of the object that are stored in the vector and outputs them to the user
}
}
}
bool Movies::increment_watched(std::string name)
{
for (Movie &obj : movies_list) // iterates through the movie objects until finds the match in name
{
if (obj.get_name() == name)
{
obj.increment_watched(); // increments watched by 1
return true;
}
}
return false;
}
movie.cpp
#include <string>
#include <iostream>
#include "Movie.h"
// constructor for initializing private members of the object
Movie::Movie(std::string name, std::string rating, int watched)
{
this->name = name;
this->rating = rating;
this->watched = watched;
}
// get methods
std::string Movie::get_name() const { return name; }
std::string Movie::get_rating() const { return rating; }
int Movie::get_watched() const { return watched; }
// display private members
void Movie::display_members() const
{
std::cout << "Name: " << get_name() << std::endl;
std::cout << "Rating: " << get_rating() << std::endl;
std::cout << "Times watched: " << get_watched() << std::endl;
std::cout << "\n" << std::endl;
}
// setter function
void Movie::increment_watched() {watched++;}
// DEBUGGING
Movie::Movie(const Movie &obj):name{obj.name}, rating{obj.rating}, watched{obj.watched} {std::cout << "copy constructor called for " << name << std::endl;}
Movie::~Movie() {std::cout << "destructor called for movie " << name << std::endl;}
Debugging the program for hours to see which parts are being copied, when copied, when destructed to get a better grasp.
Watching countless videos that explain the lifetime of the objects, copy constructors, destructors, but it still doesn't make sense for me!
push_back() takes an object and appends it at the end of the vector. It has to make a copy because it must keep the original object intact because you might need it later. If you want to avoid the copy, you’d have you use std::move to trigger the move constructor.
movies_list.push_back(std::move(temp));
However, in your example you basically want to construct an object at the end of the vector. emplace_back is just what you need; no copying or moving, just pass the constructor arguments.
movies_list.emplace_back(name, rating,watched);
What I try to do is to write all output inside a function into a file. Maybe I need a way to assign all output (not only arrays) in test_func to some kind of variable so that I can return it, but I can't figure out.
#include <iostream>
#include <fstream>
#include <functional>
using namespace std;
void test_func()
{
int a[] = {20,42,41,40};
int b[] = {2,4,2,1};
cout << "Below is the result: "<< endl;
for (int i=0; i<4; i++){
cout << "***********************" << endl;
cout << a[i] << " : " << b[i] <<endl;
cout << "-----------------------" << endl;
}
}
void write_to_file(function<void()>test_func)
{
ofstream ofile;
ofile.open("abc.txt");
ofile << test_func(); // This is not allowed
ofile.close();
}
int main()
{
write_to_file(test_func);
return 0;
}
I need to get all output from test_func instead of only the array a and b, because I have multiple functions in different formats, which are all needed to write into the file using same function write_to_file.
Is there any logical way to do this? (or alternative to function?)
Here is some code that will work the way you want. You have to replace std::couts current rdbuf() with the one of the file streams, and reset it afterwards:
void write_to_file(function<void()>test_func) {
ofstream ofile;
ofile.open("abc.txt");
std::streambuf* org = cout.rdbuf(); // Remember std::cout's old state
cout.rdbuf(ofile.rdbuf()); // Bind it to the output file stream
test_func(); // Simply call the anonymous function
cout.rdbuf(org); // Reset std::cout's old state
ofile.close();
}
Here you can see it running as you intended: Demo
To overcome the problem with the varying function signatures, you can use a delegating lambda function:
void test_func2(double a, int b) {
cout << a << " * " << b << " = " << (a * b) << endl;
}
int main() {
// Create a lambda function that calls test_func2 with the appropriate parameters
auto test_func_wrapper = []() {
test_func2(0.356,6);
};
write_to_file(test_func_wrapper); // <<<<< Pass the lambda here
// You can also forward the parameters by capturing them in the lambda definition
double a = 0.564;
int b = 4;
auto test_func_wrapper2 = [a,b]() {
test_func2(a,b);
};
write_to_file(test_func_wrapper2);
return 0;
}
Demo
You can even do this with a little helper class, which generalizes the case for any std::ostream types:
class capture {
public:
capture(std::ostream& out_, std::ostream& captured_) : out(out_), captured(captured_), org_outbuf(captured_.rdbuf()) {
captured.rdbuf(out.rdbuf());
}
~capture() {
captured.rdbuf(org_outbuf);
}
private:
std::ostream& out;
std::ostream& captured;
std::streambuf* org_outbuf;
};
void write_to_file(function<void()>test_func)
{
ofstream ofile;
ofile.open("abc.txt");
{
capture c(ofile,cout); // Will cover the current scope block
test_func();
}
ofile.close();
}
Demo
So regarding your comment:
Sure, but I will require something to store those cout, or maybe there's another completely different way instead of using test_func() for the process?
We have everything at hand now to do this
#include <iostream>
#include <fstream>
#include <functional>
#include <string>
#include <sstream>
using namespace std;
void test_func1(const std::string& saySomething) {
cout << saySomething << endl;
}
void test_func2(double a, int b) {
cout << "a * b = " << (a * b) << endl;
}
class capture {
public:
capture(std::ostream& out_, std::ostream& captured_) : out(out_), captured(captured_), org_outbuf(captured_.rdbuf()) {
captured.rdbuf(out.rdbuf());
}
~capture() {
captured.rdbuf(org_outbuf);
}
private:
std::ostream& out;
std::ostream& captured;
std::streambuf* org_outbuf;
};
int main() {
std::string hello = "Hello World";
auto test_func1_wrapper = [hello]() {
test_func1(hello);
};
double a = 0.356;
int b = 6;
auto test_func2_wrapper = [a,b]() {
test_func2(a,6);
};
std::stringstream test_func1_out;
std::stringstream test_func2_out;
std::string captured_func_out;
{ capture c(test_func1_out,cout);
test_func1_wrapper();
}
{ capture c(test_func2_out,cout);
test_func2_wrapper();
}
captured_func_out = test_func1_out.str();
cout << "test_func1 wrote to cout:" << endl;
cout << captured_func_out << endl;
captured_func_out = test_func2_out.str();
cout << "test_func2 wrote to cout:" << endl;
cout << captured_func_out << endl;
}
And the Demo of course.
The line ofile << test_func(); means that returned value of called test_func(); is directed to that stream. It doesn't do anything to actions done within function called. You may pass stream to the function though.
void test_func(ostream& outs)
{
outs << "Below is the result: "<< endl;
}
and call it with cout or ofile - any ostream as argument.
void write_to_file(function<void(ostream&)>test_func)
{
ofstream ofile;
ofile.open("abc.txt");
test_func(ofile); // This is not allowed
ofile.close();
}
But if the behaviour of function as stream manipulator is something what you want, you have to design a proper operator.
ostream& operator<< (ostream& o, void(*func)(ostream&) )
{
func(o);
return o;
}
Then you can write something like
cout << test_func << " That's all, folks\n";
Note, that test_func isn't called here, its id used as expression results in function's address being passed to operator<<.
Real stream manipulators (e.g. https://en.cppreference.com/w/cpp/io/manip/setw ) implemented not as functions , but as templates of functional objects, the argument of setw in line:
is >> std::setw(6) >> arr;
is actually argument of a constructor
What I try to do is to write all output inside a function into a file.
I often use a std::stringstream to act as a temporary repository for text, i.e. the ss holds and bundles all output into a 'buffer' (a text string) for delay'd output to the file.
For your test_func, you might add a ss reference parameter :
void test_func(std::stringsteam& ss)
{
int a[] = {20,42,41,40};
int b[] = {2,4,2,1};
cout << "Below is the result: "<< endl;
for (int i=0; i<4; i++){
ss << "***********************" << endl;
ss << a[i] << " : " << b[i] <<endl;
ss << "-----------------------" << endl;
}
}
A std::stringstream is essentially a ram-based ofile (with none of the hard disk overhead).
So you can run many test_func's, lump all the output together into one ss, and empty the ss content to the one file.
Or, you might invoke 1 test_func, output / append that ss contents to your ofile, then clear the ss for re-use.
You also might invoke 1 test func, output that ss contents to a unique ofile, then clear the ss and do the next test func, etc.
Note: a) std::stringstream uses one std::string as a working buffer, and b) std::string keeps its data in dynamic memory. I seldom worry about how big the ss gets. But, if you are worried, and have an estimate, you can easily use reserve to set the string size. Knowing this size will allow you to plan to control very big output files.
Next, consider keeping stringstream out of the test_func's, and instead keep it in the outer data gathering function:
void write_to_file(function<void()>test_func)
{
std::stringstream ss; // temporary container
test_func(ss); // add contributions
test_func2(ss); // add contributions
test_func3(ss); // add contributions
// ...
test_funcN(ss); // add contributions
// when all testing is complete, output concatenated result to single file
ofstream ofile;
ofile.open("abc.txt");
ofile << ss.str();
ofile.close();
}
int main()
{
write_to_file(test_func);
return 0;
}
Note: to empty a ss, I use 2 steps:
void ssClr(stringstream& ss) { ss.str(string()); ss.clear(); }
// clear data clear flags
Note: I encapsulate my coding efforts into one or more c++ classes. In my code, the ss objects are declared as a data attribute of my class, and thus accessible to all function attributes of that class, including each test_funci (i.e. no need to pass the ss)
I am new to your forum, so please forgive any missteps. I am working on a c++ project that reads and writes to a binary file. I first tried doing this using full on c++ but when an error popped up, my instructor told me to use c style file manipulation. Low and behold, I get the same error:
Unhandled exception at 0x6087CCC8 (msvcp110d.dll) in CSI_FinalProj_EmployeeDB.exe: 0xC0000005: Access violation reading location 0x00CDDAEC.
This occurs after successfully completing the read and print, and successfully closing the file. It always occurs when the program exits the function and attempts to return to the calling function. If I put it in the main, it blows up after the return, when the program ends.
The function is a simple print function:
void fileClerkType::printRecord(int id)const
{
FILE* spRead;
employeeType record;
long location;
long size;
location = id - 1;
size = sizeof(employeeType);
spRead = fopen("companyFile.dat", "r");
fseek(spRead, location*size, SEEK_SET);
fread(&record, sizeof(employeeType), 1, spRead);
// If a record has been deleted, the id will be 0
// In that case, don't print
if (record.getEmployeeID() != 0)
{
cout << record << endl;
fread(&record, sizeof(employeeType), 1, spRead);
}
fclose(spRead);
}//Unhandled exception at 0x5065CCC8 (msvcp110d.dll) in
//CSI_FinalProj_EmployeeDB.exe: 0xC0000005: Access violation
//reading location 0x00CDDAEC.
As I said, the function works perfectly. employeeType is a class that has:
2 ints, three strings, and a float
Here is the original c++ version with the same problem. The only difference is that this prints all of the records. It also works perfectly.:
void administratorType::showAllRecords()
{
long test;
long position = 0;
long recordSize = sizeof(employeeType);
ifstream inFile("EmployeesNew.dat", ios::in | ios::binary);
employeeType buffer; // empty employeeType
if(inFile.is_open())
{
inFile.seekg((position * recordSize), ios::beg);
test = inFile.peek(); // Debug
inFile.read(reinterpret_cast<char*>(&buffer), recordSize);
position = 0;
while(position < getRecordCount())
{
inFile.seekg((position * recordSize), ios::beg);
test = inFile.peek();
inFile.read(reinterpret_cast<char*>(&buffer), recordSize);
outputRecord(cout, buffer);
position++;
}
inFile.close();
}
}// Runs fine to here, but throws error when leaving the function
// Unhandled exception at 0x5408CCC8 (msvcp110d.dll) in
// ProjectName.exe: 0xC0000005: Access violation
// reading location 0x0137D3B4.
It has to be an implementation issue. But I cannot see it. Is there something in the implementation that is causing the pointers keeping track of function calls and returns to be corrupted? Thank you in advance for your help.
Sorry, here is the list of member variables for the Employee class. They are not fixed length strings:
int age;
int employeeID; // Auto-generated
float salary;
string lastName;
string firstName;
string ssn;
std::string is not a trivially copyable type, so no class that has one as a member is trivially copyable either.
You cannot read or write to non-trivially copyable types bytewise like this. The function might not crash when you read from the string due to most libraries having adopted SSO (assuming lastName, firstName, and ssn are short enough), but you'll still run into issues during destruction.
The canonical way to serialize data in c++ is to overload the stream operator, here's an example:
std::istream& operator>>(std::istream& stream, employeeType& employee)
{
return stream >>
employee.age >>
employee.employeeID >>
employee.salary >>
employee.lastName >>
employee.firstName >>
employee.ssn;
}
std::ostream& operator<<(std::ostream& stream, employeeType const& employee)
{
return stream <<
employee.age << ' ' <<
employee.employeeID << ' ' <<
employee.salary << ' ' <<
employee.lastName << ' ' <<
employee.firstName << ' ' <<
employee.ssn << '\n';
}
Records can be read or written in a loop with something like
for (employeeType e; inFile >> e;)
//do something with e
Or you can even copy them into a vector with
std::vector<employeeType> employees(
std::istream_iterator<employeeType>(inFile),
std::istream_iterator<employeeType>()
);
I created a struct to hold the data being read to the file, then converted all strings to char arrays. Doing each of those did not work, but the combination did. The following is the test program with a main() and a test class (with a struct. This is what I used to find the solution. This is a working program for those of you seeking a way to read/write binary files randomly (unless I screwed it up while formatting it in here).
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
struct STUDENT
{
char lName[21];
int id;
float sal;
};
class Person
{
public:
struct STUDENT student;
string getlName() const
{
return student.lName;
}
int getID() const
{
return student.id;
}
float getSal() const
{
return student.sal;
}
// Insertion operator
friend std::ostream& operator<<(std::ostream& os, const Person& p)
{
// write out individual members of the struct with
// an end of line between each one
os << p.student.id << ' ' << p.student.lName
<< ' ' << p.student.sal << '\n';
return os;
}
// Extraction operator
friend std::istream& operator>>(std::istream& is, Person& p)
{
// read in individual members of struct
is >> p.student.id >> p.student.lName >> p.student.sal;
return is;
}
Person()
{
}
};
void outputLine( ostream&, const STUDENT&);
int main()
{
char lName[21] = {}; // Extra char for null
int id;
float sal;
int size = sizeof(STUDENT);
string more;
bool exit_now = false;
STUDENT buffer;
Person person;
// In order to randomly access data without destroying the file,
// you must use in and out (read/write mode).
fstream outFile("testFile.dat", ios::in | ios::out | ios::binary);
// Ensure file is opened
if(!outFile)
{
cerr << "Error: Out File could not be opened" << endl;
exit(1);
}
// ************* Random access inserting *************
do
{
cout << "Enter last Name\n?";
cin.getline(lName, 21);
int test;
test = strlen(lName); // FYI: this works to get char count
cout << "Enter salary\n?";
cin >> sal;
cout << "Enter ID\n?";
cin >> id;
strcpy_s(person.student.lName, lName); // copy input to struct
person.student.sal = sal;
person.student.id = id;
cout << person; // object being printed
outFile.seekp((person.student.id - 1) * size);
outFile.write(reinterpret_cast<const char* >(&person.student), size);
// Need this to get the next name
cin.clear();
cin.ignore();
cout << "Do you want to add another record? (yes or no)\n?"
<< endl;
cin >> more;
if (more == "no")
exit_now = true;
// Need this to get the next name properly
cin.clear();
cin.ignore();
}while(exit_now == false);
outFile.close();
// ************* Display Data *************
fstream inFile("testFile.dat", ios::in);
if(inFile) // Is there a connection
{
int target = 0;
int index = 0;
int position;
cout << "All records:" << endl;
while(inFile)
{
inFile.read(reinterpret_cast<char*>(&buffer), size);
if (buffer.id > 0)
{
target = inFile.tellg(); // Debug
cout << buffer.lName << endl;
}
//cout << buffer << endl; // This works
//cout << buffer.id << endl; // This works
}
cout << endl << "Search for a record by id" << endl << endl;
cout << "Enter an id: (0 to exit)" << endl;
cin >> target;
while(target > 0)
{
index = target - 1;
inFile.clear(); // Clear the flags. If the fail flags are
// are set, seekg() will not work.
// Position the file pointer
inFile.seekg(sizeof(Person)*index, ios::beg);
// Read information into the buffer (Person object)
// starting at the file pointer
inFile.read(reinterpret_cast<char*>(&buffer), size);
cout << buffer.lName << endl;
outputLine(cout, buffer);
cout << "Enter an id: (0 to exit)" << endl;
cin.clear();
cin >> target;
}
inFile.close();
cin.clear();
cin.get();
}else
cerr << endl << "Error: Could not complet the file connection."
<< "\nData could not be read."<< endl;
return 0;
}
void outputLine( ostream& output, const STUDENT& record)
{
//output << record << endl; // This works also
output << left << setw(20) << record.lName
<< setw(5) << record.id << setprecision(2)
<< right << fixed << showpoint
<< record.sal << endl;
}
I cannot write data on a file with these pointer variables in the class. there is no error in the program but no data is written on the file.
kindly someone tell me that where i am doing something wrong.
#include <iostream.h>
#include <fstream.h>
class studentinfo
{
private:/*Creating Private Data Members */
char* VUID;
char* campusID;
char* Studentname;
char* Fathername;
public:
void Storefile();/* Function to Store Data in the File*/
char Display();/*Function to Read and then Display Data from the File*/
studentinfo(char*, char*, char*, char*);/*Constructor to initialize Data Members*/
~studentinfo();
};
/* Constructor Defined Here*/
studentinfo::studentinfo(char* VUID, char* campusID, char* Studentname, char* Fathername)
{
cout << "Parameterized Contructor is Called" << endl << endl;
}
/*Destructor Defined Here*/
studentinfo::~studentinfo()
{
cout << "Destructor Called for destruction of the object" << endl;
system("pause");
}
/*Function to Store Data in the File Defined here*/
void studentinfo::Storefile()
{
ofstream re;
re.open("record.txt");
if(!re)/*Error Checking Mechanism*/
{
cout<<"Error Reading File"<<endl;
}
re << VUID << endl << campusID << endl << Studentname << endl << Fathername << endl;/*Using data members to Store data in the File*/
cout << "All the Data Members are Stored in a File" << endl << endl;
re.close();
}
/*Function to Read and then Display the data in the File is definde here */
char studentinfo::Display()
{
char output[100];/*Array to store and display the data*/
ifstream reh;
reh.open("record.txt");
if(!reh)
{
cout << "Error Reading File" << endl;
}
cout << "Following is My Data" << endl << endl;
while(!reh.eof()){
reh.getline(output, 100, '\n');/*Reading the data and storing it in the 'output' array line by line*/
cout << output << endl;
}
reh.close();
}
/*Main Function starting here*/
main()
{
studentinfo s1("mc130202398", "PMTN08", "Rehan Shahzad Siddiqui","Rizwan Ali Siddiqui");/*Object Created and Initialized by constructor calling*/
s1.Storefile();/*Function Call*/
s1.Display();/*Function Call*/
system("pause");
}
Your constructor is broken and leaves all the pointers unassigned. You can't use a variable's value until you assign it one.
Also, what crappy compiler are you using or what warnings settings do you have? Your constructor is being passed pointers to constants but it takes non-const pointers. That should definitely have caused a warning, pointing to your mishandling of these pointers.
studentinfo s1("mc130202398", "PMTN08", "Rehan Shahzad Siddiqui","Rizwan Ali Siddiqui");/*Object Created and Initialized by constructor calling*/
Notice you pass the constructor a bunch of constants.
studentinfo::studentinfo(char* VUID, char* campusID, char* Studentname, char* Fathername)
Oops, but the constructor takes regular char* pointers. So what are these pointers supposed to point to?
Tip: Use sensible C++ classes like std::string and these problems will magically go away.
A rewrite that addresses a number of points:
Removes the need to add using namespace std;
Uses std::string for the studentinfo member variables as per David Schwartz's recommendation
Uses a constructor initialisation list to set member variables
Replaces the unreliable eof() check
Let me know if you have any further questions.
#include <iostream>
#include <fstream>
#include <string>
class studentinfo
{
private:/*Creating Private Data Members */
std::string m_VUID;
std::string m_campusID;
std::string m_Studentname;
std::string m_Fathername;
public:
void Storefile();/* Function to Store Data in the File*/
void Display();/*Function to Read and then Display Data from the File*/
studentinfo(std::string, std::string, std::string, std::string);/*Constructor to initialize Data Members*/
~studentinfo();
};
/* Constructor Defined Here*/
studentinfo::studentinfo(std::string VUID, std::string campusID, std::string Studentname, std::string Fathername)
: m_VUID(VUID)
, m_campusID(campusID)
, m_Studentname(Studentname)
, m_Fathername(Fathername)
{
std::cout << "Parameterized Contructor is Called" << std::endl << std::endl;
}
/*Destructor Defined Here*/
studentinfo::~studentinfo()
{
std::cout << "Destructor Called for destruction of the object" << std::endl;
}
/*Function to Store Data in the File Defined here*/
void studentinfo::Storefile()
{
std::ofstream re;
re.open("record.txt");
if(!re)/*Error Checking Mechanism*/
{
std::cout << "Error opening file" << std::endl;
}
// Using data members to store data in the file
re << m_VUID.c_str() << std::endl;
re << m_campusID.c_str() << std::endl;
re << m_Studentname.c_str() << std::endl;
re << m_Fathername.c_str() << std::endl;
std::cout << "All the data members are stored in a file" << std::endl << std::endl;
re.close();
}
/* Function to read and then display the data in the file is defined here */
void studentinfo::Display()
{
std::string in;/*Array to store and display the data*/
std::ifstream reh("record.txt");
if(!reh)
{
std::cout << "Error Reading File" << std::endl;
}
std::cout << "Following is My Data" << std::endl << std::endl;
while(std::getline(reh, in))
{
std::cout << in << std::endl;
}
reh.close();
}
/* Main Function starts here*/
void main()
{
// Object created and initialised by calling constructor
studentinfo s1("mc130202398", "PMTN08", "Rehan Shahzad Siddiqui","Rizwan Ali Siddiqui");
s1.Storefile(); /*Function Call*/
s1.Display(); /*Function Call*/
system("pause");
}
How do you create multiple new class objects using the default class constructor?
For a project I am having to write a program that writes three class objects into a file. That I have done... The next part is being able to read the data back into three separate class objects using a readData function and then displaying the data. I am completely lost at how to do this so I don't have any code in the readData function.
Here is an example of what the object looks like when it is being written to the file.
employee name(21, "first last", "45 East State", "661-9000", 30, 12.00);
Here is the bulk of my code the employee class is fairly basic but here is the default class constructor.
employee::employee ();
employee::employee(int locEmpNumber, string locName, string locaddress, string locphone, double locHrWorked, double locHrWage)
#include "employee.h"
#include <string>
#include <iomanip>
#include <iostream>
#include <fstream>
using namespace std;
void writeData (const employee& e);
void readData (const employee& e);
void printCheck (const employee& e);
int main( )
{
//Declarations
const int ONE = 1;
const int TWO = 2;
int userInput;
cout << "This program has two options:" << endl;
cout << "1 - Create a data files called 'EmployeeInfo.txt', or" << endl;
cout << "2 - Read data from a file and print paychecks." << endl;
cout << "Please enter (1) to create a file or (2) to print checks: ";
cin >> userInput;
if (userInput == ONE)
{
//Create employee objects:
employee joe(37, "Joe Brown", "123 Main St.", "123-6788", 45, 10.00);
employee sam(21, "Sam Jones", "45 East State", "661-9000", 30, 12.00);
employee mary(15, "Mary Smith", "12 High Street", "401-8900", 40, 15.00);
ofstream empFile ("EmployeeInfo.txt");
//Employee objects to write themselves out to the file.
writeData(joe);
writeData(sam);
writeData(mary);
//Close the file.
empFile.close();
//Print an message that creation of the file is complete.
system("CLS");
cout << "\nCreation of 'EmployeeInfo.txt' has completed.\n";
cout << "\nYou can now run option 2.\n";
//Exit.
system("PAUSE");
return 0;
}
else if (userInput == TWO)
{
//Create three new Employee objects, using the default Employee constructor.
//Open the file that you just saved.
//Have each object read itself in from the file.
//Call the printCheck( ) function for each of the three new objects, just as you did in the previous project.
}
else
{
system("CLS");
cout << "Incorrect entry.... Please try again and follow directions closely! \n" << endl;
system("PAUSE");
return 0;
}
}
void writeData(const employee& e)
{
fstream empFile;
empFile.open ("EmployeeInfo.txt", ios::app);
empFile << e.getEmpNumber() << "\n";
empFile << e.getName() << "\n";
empFile << e.getAddress() << "\n";
empFile << e.getPhone() << "\n";
empFile << e.getHrWorked() << "\n";
empFile << e.getHrWage() << "\n";
}
void readData(const employee& e)
{
fstream empFile;
empFile.open ("EmployeeInfo.txt", ios::in);
if(empFile.fail())
{
cout << "File could not be open. Please try option 1 then option 2.\n" << endl;
return;
}
}
It's good to see that you have made an effort at solving the problem. However, there is a mismatch between what you set out in your question and some of the comments in your code. It seems clear to me that a key part of your brief is that the employee object itself is required to be able to write itself to the file and to read itself back from the file.
You have written code that will write the contents of the object to the file rather than having the object write itself to the file. It might seem like I'm splitting hairs on this one, but this is the essence of what Object Oriented Programming is about. Encapsulating the functionality within the object itself is the real goal here.
I've included some code below to help you. Hopefully this will make good sense for you.
class employee
{
private:
int _locEmpNumber;
std::string _locName;
std::string _locAddress;
std::string _locPhone;
double _locHrWorked;
double _locHrWage;
public:
employee();
employee(int locEmpNumber, std::string locName, std::string locAddress, std::string locPhone, double locHrWorked, double locHrWage);
//object should be able to save itself as per your project brief.
void writeData(std::ofstream &empFile);
//object should be able to read itself from file as per your project brief
void readData(std::ifstream &empFile);
};
employee::employee()
{
_locEmpNumber = 0;
_locHrWorked = _locHrWage = 0;
}
employee::employee(int locEmpNumber, std::string locName, std::string locAddress, std::string locPhone, double locHrWorked, double locHrWage)
{
_locEmpNumber = locEmpNumber;
_locName = locName;
_locAddress = locAddress;
_locPhone = locPhone;
_locHrWorked = locHrWorked;
_locHrWage = locHrWage;
}
//
//From what I can glean from your brief ...
//Employee objects to write themselves out to the file!!!
void employee::writeData(std::ofstream &empFile)
{
empFile << _locEmpNumber << std::endl;
empFile << _locName << std::endl;
empFile << _locAddress<< std::endl;
empFile << _locPhone << std::endl;
empFile << _locHrWorked << std::endl;
empFile << _locHrWage << std::endl;
}
//
//Again, from what I can glean from your brief ...
//Have each object read itself in from the file!!!
void employee::readData(std::ifstream &empFile)
{
//Normally you would have error handling in a method like this and
//would either return a response that indicates that the operation
//succeded or failed. You might alternatively use exception handling
//or indeed a combination of both.
//
//Normally you would reset all members to initial / empty values before
//reading values into them from your file. In this case we will omit that
//for the purposes of simplicity. The main reason you would reset members
//is to ensure that when reusing an object you don't end up with partial
//data from the current "read" operation mixed with partial data that
//was already in the object before you started reading.
std::string inputStr;
std::getline(empFile, inputStr);
_locEmpNumber = atoi(inputStr.c_str());
std::getline(empFile, _locName);
std::getline(empFile, _locAddress);
std::getline(empFile, _locPhone);
std::getline(empFile, inputStr);
_locHrWorked = atof(inputStr.c_str());
std::getline(empFile, inputStr);
_locHrWage = atof(inputStr.c_str());
}
int main(int argc, char* argv[])
{
//Declarations
const int ONE = 1;
const int TWO = 2;
int userInput;
std::cout << "This program has two options:" << std::endl;
std::cout << "1 - Create a data files called 'EmployeeInfo.txt', or" << std::endl;
std::cout << "2 - Read data from a file and print paychecks." << std::endl;
std::cout << "Please enter (1) to create a file or (2) to print checks: ";
std::cin >> userInput;
if (userInput == ONE)
{
//Create employee objects:
employee joe(37, "Joe Brown", "123 Main St.", "123-6788", 45, 10.00);
employee sam(21, "Sam Jones", "45 East State", "661-9000", 30, 12.00);
employee mary(15, "Mary Smith", "12 High Street", "401-8900", 40, 15.00);
std::ofstream empFile ("EmployeeInfo.txt");
//Employee objects to write themselves out to the file.
joe.writeData(empFile);
sam.writeData(empFile);
mary.writeData(empFile);
// writeData(joe);
// writeData(sam);
// writeData(mary);
//Close the file.
empFile.close();
//Print an message that creation of the file is complete.
system("CLS");
std::cout << "\nCreation of 'EmployeeInfo.txt' has completed.\n";
std::cout << "\nYou can now run option 2.\n";
//Exit.
system("PAUSE");
return 0;
}
else if (userInput == TWO)
{
//Create three new Employee objects, using the default Employee constructor.
employee joe;
employee sam;
employee mary;
//Open the file that you just saved.
std::ifstream empFile("EmployeeInfo.txt");
//Have each object read itself in from the file.
joe.readData(empFile);
sam.readData(empFile);
mary.readData(empFile);
empFile.close();
//Call the printCheck( ) function for each of the three new objects, just as you did in the previous project.
//I'll leave it to you to add this yourself.
}
else
{
system("CLS");
std::cout << "Incorrect entry.... Please try again and follow directions closely! \n" << std::endl;
system("PAUSE");
return 0;
}
return 0;
}