How these two function differs? Is there any different kinds of istream other than std::cin and what is the point of returning the istream?
using namespace std;
istream& readInput(istream& in, vector<string>& wordList)
{
string word;
while (in >> word)
{
wordList.push_back(word);
}
in.clear();
return in;
}
void readInput(vector<string>& wordList)
{
string word;
while (cin >> word)
{
wordList.push_back(word);
}
cin.clear();
}
cin is absolutely not the only one istream, I think that it is not even the most used one. Read about e.g. ifstream and istringstream.
Returning istream& from the function may be useful in various situations - it depends on the context. For just simple calls of readInput one can skip it and make the function void.
Related
I've been trying to write the below object into a file and got lot of trouble since strings are dynamically allocated.
class Student{
string name, email, telephoneNo;
int addmissionNo;
vector<string> issued_books;
public:
// There are some methods to initialize name, email, etc...
};
So I got to know that I can't just write into a file or read from a file an object with serialization. So I searched all over the internet about serialization with cpp and got to know about Boost library.But I wanted to do it my own (I know writing a library that already exist is not good, but I wanna see what's going on inside the code). So I got to know about overloading iostream << and >>. And I also know that serialize/deserialize into/from text.
But I want to serialize into a binary file. So I tried overloading ostream write and istream read. But then I got size issues(as write and read needs the sizeof the object it writes/reads).Then I also got to know about stringstream can help to serialize/deserialize objects into/from binary. But I don't how to do that?
So my real question is How to serialize and deserialize an object into/from binary files without third party libraries?
I have found a solution serialize and deserialize an object into/from a file. Here is an explaination
As I told you this is my class. And I have added two functions which overload the iostream's write and read.
class Student{
string name, email, telephoneNo;
int addmissionNo;
vector<string> issuedBooks;
public:
void create(); // initialize the private members
void show(); // showing details
// and some other functions as well...
// here I'm overloading the iostream's write and read
friend ostream& write(ostream& out, Student& obj);
friend istream& read(istream& in, Student& obj);
};
But I have also told you that I have tried this already. The problem I have was how to read without object member's size. So I made changes as below (Please read comments also).
// write: overload the standard library write function and return an ostream
// #param out: an ostream
// #param obj: a Student object
ostream& write(ostream& out, Student& obj){
// writing the objet's members one by one.
out.write(obj.name.c_str(), obj.name.length() + 1); // +1 for the terminating '\0'
out.write(obj.email.c_str(), obj.email.length() + 1);
out.write(obj.telephoneNo.c_str(), obj.telephoneNo.length() + 1);
out.write((char*)&obj.addmissionNo, sizeof(obj.addmissionNo)); // int are just cast into a char* and write into the object's member
// writing the vector of issued books
for (string& book: obj.issuedBooks){
out.write(book.c_str(), book.length() + 1);
}
return out;
}
// read: overload the standard library read function and return an istream
// #param in: an istream
// #param obj: a Student object
istream& read(istream& in, Student& obj){
// getline is used rather than read
// since getline reads a whole line and can be give a delim character
getline(in, obj.name, '\0'); // delimiting character is '\0'
getline(in, obj.email, '\0');
getline(in, obj.telephoneNo, '\0');
in.read((char*)&obj.addmissionNo, sizeof(int));
for (string& book: obj.issuedBooks){
getline(in, book, '\0');
}
return in;
}
As you can see I have wrote length+1 for the terminating '\0'. It is usefull in read function as we have used getline instead of read. So getline reads until the '\0'. So no need of a size. And here I'm writing and reading into/from a file.
void writeStudent(Student s, ofstream& f){
char ch; // flag for the loop
do{
s.create(); // making a student
f.open("students", ios::app | ios::binary); // the file to be written
write(f, s); // the overloaded function
f.close();
cout << "Do you want to add another record? (y/n): ";
cin >> ch;
cin.ignore();
} while(toupper(ch) == 'Y'); // loop until user stop adding records.
}
void readStudent(Student s, ifstream& f){
char ch; // flag for the loop
do{
f.open("students", ios::in | ios::binary);
cout << "Enter the account no of the student: ";
int no;
cin >> no;
int found = 0;
while (read(f, s)){
if (s.retAddmissionNo() == no){
found = 1;
s.show();
}
}
if (!found)
cout << "Account Not found!\n";
f.close();
cout << "Do you want another record? (y/n): ";
cin >> ch;
} while(toupper(ch) == 'Y');
}
That's how I solved my problem. If something wrong here please comment. Thank you!
I want to be able to make a function GetInput() which takes a class as a parameter, and returns whatever is input. The function definition would look like this:
GetInput(class type) {
if (type == string) {
string stringInput;
cin >> stringInput;
return stringInput;
}
else if (type == int) {
int intInput;
cin >> intInput;
return intInput;
}
else {
return NULL;
}
}
I don't know what to write for the return type of the function because it can be either string or int. How can I make this function work?
You can't make it an actual argument, but you can do something similar by creating a function template (also called a template function):
template<class T>
T GetInput() {
T input;
cin >> input;
return input;
}
You can use it like this:
string stringInput = getInput<string>();
int intInput = getInput<int>();
getInput<string> and getInput<int> are considered different functions, generated by the compiler - hence why this is called a template.
Note - if you're using multiple files, the whole template definition must go in a header file and not the source file, because the compiler needs to see the whole template in order to generate functions from it.
As you've described it, you can't get it to work.
However, since the caller needs to know what type is being read, the simple solution is to use a templated function.
#include <iostream>
// it is inadvisable to employ "using namespace std" here
template<class T> T GetInput()
{
T Input;
std::cin >> Input;
return Input;
}
And to use
// preceding code that defines GetInput() visible to compiler here
int main()
{
int xin = GetInput<int>();
std::string sin = GetInput<std::string>();
}
The templated function will work for any type T for which input streams (like std::cin) support streaming and that can be returned by value. You can use various techniques (traits, partial specialisation) to enforce constraints (e.g. produce a meaningful compilation error if the function is used for a type for which the function logic does not work) or to provide different functionality for different types.
Of course, since all you're doing is reading from std::cin, you could actually read directly
#include <iostream>
int main()
{
int xin;
std::string sin;
std::cin >> xin;
std::cin >> sin;
}
I'm working on a problem 4-6 from Accelerated C++. The question asks that I rewrite the Student_info struct, read() function, and grade() function, so that the final grade is calculated immediately and then stored as the only grade in Student_info.
Previously, the program worked as follows:
read() reads from an input stream and stores the data into a Student_info object
Each object is added to a vector
Once every object is read and added, grade() is called on every Student_info object in the vector
With the new constraints I feel I must combine the read() and grade() functions, so there is no need to store intermediate grades. The problem is when reading from the stream I don't know I have run into the end of file, until I do. When doing this I try to call the grade() function on the end of file data.
I don't see a workaround considering the constraint is to read and then immediately work on the data. How can this be handled?
struct Student_info
{
std::string name;
double final_grade;
};
istream& read(istream& is, Student_info& s)
{
double midterm, final;
is >> s.name >> midterm >> final;
// Error, when EOF is read, grade() will process bad data
s.final_grade = grade(midterm, final);
return is;
}
void main()
{
vector<Student_info> students;
Student_info record;
while (read(cin, record))
students.push_back(record);
}
You can check whether the record was successfully read inside the read function. For example like this:
istream& read(istream& is, Student_info& s)
{
string name;
double midterm, final;
if( is >> name >> midterm >> final ) {
s.name = name;
s.final_grade = grade(midterm, final);
}
return is;
}
Note that you could read directly into s.name as in your original code, but my implementation has transaction semantics: it either reads the whole structure or leaves it alone in case it failed to read all the fields.
I have a C++ code with
ifstream myfile;
myfile.open("input");
and then has commands like:
myfile.getline(inp,256);
Question: How can I modify myfile.open("input") so that myfile is associated with cin instead of "input"?
I don't want to change all myfile.getline commands to cin.getline.
Declaring myfile=cin does not compile.
Use an istream& reference instead:
std::istream& myfile(std::cin);
Separate it out into a function and take the std::istream& as an argument. Then you can execute on both std::cin and myfile as you wish.
You can put your code into a function that takes a reference to a std::istream, e.g.
void process_data( std::istream & istr )
{ ... }
Then you can call this function both with any std::ifstream and with std::cin:
std::ifstream myfile;
...
process_data( myfile );
process_data( std::cin );
If you insist in using an std::ifstream you can replace the std::streambuf of the base std::istream (std::ifstream overloads rdbuf() so you can't use it directly):
std::ifstream file;
if (use_cin) {
file.std::istream::rdbuf(std::cin.rdbuf());
}
I'm sure this is a simple issue, but I am having trouble solving it:
I receive this from the compiler:
cdcheck.cpp|31|error: 'slectionsIn' was not declared in this scope
the offending blocks of code:
in main:
...snip
ifstream selectionsIn (argv[2]);
PlayListItem item;
int itemCount = 0;
while (slectionsIn >> item)
{
...snip
in PlayListItem.cpp:
std::istream& operator>> (std::istream& in, PlayListItem& pl){
I can post the contents of these files if needed. It should be noted that this compiles correctly if I change from istream to ifstream in the declaration, but I can not modify PlayListItem.cpp, only main.
Try fixing the misspelled identifier that was mentioned in the compiler error message:
while (selectionsIn >> item) // not: slectionsIn
Compare
ifstream selectionsIn(argv[2]);
to
while (slectionsIn >> item)