I understand how to implement a overloaded ostream operator but I'm a little confused on a overloaded istream operator. All the examples online only show a brief demonstration (i.e. is >> val; ) which doesn't help me in context with my class variables and methods. In my main, I'm trying to read in a file and replace the pointers contents with the file contents. I have a factory method and read method that does that already but I'm trying to overload my istream operator to do the same. However, although the pointers contents are replaced, I still receive the cerr message below. Am I supposed to pass something to the ifs in my >> function?
Here is my main
int main() {
// factory method instantiates all class variables
Base *aa = Base::create(file); // it works
ifstream in(file2);
if((in >> *aa).fail()) // Read file contents
cerr << "Read failed" << '\n';
cout << *aa; // prints vector contents
}
Prints
// file // file2 cout << *aa SupposedToBe
555 111 Read Failed 111
555 222 111 222
555 333 222 333
333
What I have so far (.cpp)
istream &operator>>(istream &ifs, Base &val) {
string line;
getline(ifs, line); // type of file
if(line == "type1")
val.filetype = "type1";
if(line == "type2")
val.filetype = "type2";
val.vec.clear(); // clear old vector
vector<int> inner; // inner vec to push onto main vec
// read remaining contents
while(getline(ifs, line)) {
for(size_t i = 0; i < line.length(); i++)
inner.push_back(line[i]);
val.vec.push_back(inner);
inner.clear();
}
val.height = val.vec.size();
val.width = val.vec[0].size();
val.max = val.vec[height-1][width-1];
return ifs;
}
My overloaded ostream function looks a lot different that what is displayed above (i.e. lots of os << value). But, whenever I do ifs >> value, I get all kinds of compiler errors (i.e. I tried just doing ifs >> val.image; ifs >> val.height; etc. but all I got was compiler errors). What am I supposed to pass to the istream (in the above function) so the error above (below main) doesn't display.
.h file for reference
class Base
{
protected:
std::vector<std::vector<int> > vec;
std::string filetype;
int width, height, max;
Base() = default;
Base &operator=(const Base &) = default;
public:
static Base* create(std::string filename);
virtual ~Base();
// read by derived class
virtual void read(std::string filename) = 0;
friend std::istream &operator>>(std::istream &, Base &);
friend std::ostream &operator<<(std::ostream &, const Image &);
};
Use of
if((in >> *aa).fail()) // Read file contents
cerr << "Read failed" << '\n';
is a problem. The way you have implemenented operator>>(std::istream &, Base &)
, that logic is bound to fail every time.
You have a loop in the function
while(getline(ifs, line)) {
...
}
That loop will break only when there is nothing to read from the file or there is an error in reading the contents of the file. When that loop exits, ifs.fail()
will always be true.
You should replace the if
statement with just:
in >> *aa;
If you need to do any error checking and print appropriate error messages, that has to be done inside operator>>(std::istream &, Base &)
.
One way to make sure that the istream
does not get to the point where ifs.fail()
is always true
is to know what's expected ahead of time.
If the number of lines expected in the file is the first input, then, it is possible to read all the data and return from the function such that ifs.fail()
is false
.
Sample input:
type1
3
111
222
333
Then, the oprator>>
function can be defined as:
std::stream& operator>>(std::istream& ifs, Base& val)
{
std::string line;
if ( !getline(ifs, line) ) // type of file
{
// Problem reading. No point trying to read more.
return ifs;
}
if(line == "type1")
val.filetype = "type1";
if(line == "type2")
val.filetype = "type2";
// read remaining contents
int numLines = 0;
if ( !(ifs >> numLines) )
{
// Problem reading. No point trying to read more.
return ifs;
}
val.vec.clear(); // clear old vector
vector<int> inner; // inner vec to push onto main vec
for ( int n = 0; n < numLines; ++n )
{
if ( !getline(ifs, line))
{
// Problem reading. No point trying to read more.
return ifs;
}
for(size_t i = 0; i < line.length(); i++)
{
inner.push_back(line[i]);
}
val.vec.push_back(inner);
inner.clear();
}
val.height = val.vec.size();
val.width = val.vec[0].size();
val.max = val.vec[height-1][width-1];
return ifs;
}