Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I initialize a reference to `ofstream` / `ifstream`, with an instance of `fstream`?

INTRODUCTION

void  read_foo (std::ifstream& out);
void write_foo (std::ofstream& out);

I have these two functions where one is supposed to read from a file, and the other is supposed to write to one.

Everything works having the below snippets;

std::ifstream ifs ("filename.txt");
read_foo  (ifs);

std::ofstream ofs ("filename.txt");
write_foo (ofs);

THE PROBLEM

However, if I try to use a std::fstream, so I can call both functions with the same stream, it doesn't compile, and the compiler spits out a lot of error messages.

  • Why can't I bind a fstream to an ifstream&, or ofstream&?

foo.cpp

#include <fstream>

void  read_foo (std::ifstream& out);
void write_foo (std::ofstream& out);

int main () {
  std::fstream fs ("filename.txt");

   read_foo (fs);
  write_foo (fs);
}

Error(s):


foo.cpp: In function ‘int main()’:
foo.cpp:9:16: error: invalid initialization of reference of type ‘std::ifstream& {aka std::basic_ifstream<char>&}’ from expression of type ‘std::fstream {aka std::basic_fstream<char>}’ read_foo (fs);
^
foo.cpp:3:7: note: in passing argument 1 of ‘void read_foo(std::ifstream&)’ void read_foo (std::ifstream& out);


foo.cpp:10:16: error: invalid initialization of reference of type ‘std::ofstream& {aka std::basic_ofstream<char>&}’ from expression of type ‘std::fstream {aka std::basic_fstream<char>}’
write_foo (fs);
^
foo.cpp:4:6: note: in passing argument 1 of ‘void write_foo(std::ofstream&)’ void write_foo (std::ofstream& out);

like image 879
Filip Roséen - refp Avatar asked Jun 06 '14 07:06

Filip Roséen - refp


1 Answers

"THE LONG STORY; SHORT" - ANSWER

Since a std::fstream is not derived from either std::ofstream, nor std::ifstream, the reference is not "compatible" with the instance of std::fstream.

Use std::istream& and std::ostream&, instead of std::ifstream& and std::ofstream& (respectively).

void write_data (std::ostream&);
void  read_data (std::istream&);

INTRODUCTION

As the compiler is trying to tell you; std::fstream does not inherit from std::ifstream, therefore you cannot initialize a reference to the latter with a value of the former.

I've stumbled upon several developers who seem to assume that std::fstream, behind the scenes, is some sort of direct merge between a std::ifstream, and a std::ofstream, and that it is implemented by deriving from both.

When asked why they think that is the case, many think that the answer can be summed up with; "because it makes sense, right?"


THE SILLY ANALOGY

Imagine that we have three siblings; Ivan, Owen, and John, living in a family where reading and writing is everything.

All brothers were born with a gift;

  • Ivan is great at reading, and has given it his whole life, he never does anything else, and;
  • Owen has a thing for writing, which is odd since he can't read, and;
  • John got lucky and got both the skill of reading and writing.

Just because John can do both of the things his brothers can, doesn't mean that they are his parents - they are, after all; his brothers.

All three brothers has inherited their certain traits from other relatives, not each other.


THE ANSWER

std::fstream is not built "on top of" std::{i,o}fstream, even though they share certain parts of their individual inheritance tree.


iostreams inheritance visualized

src: http://en.cppreference.com/w/cpp/io


When accepting a stream in generic code you should not care about the "real" type of the underlying stream.

Does it really matter if we pass in a std::stringstream, std::fstream, or std::ofstream to our function which writes some output data to a stream? No, all we care about is the ability to read/write.

We express this by forming a reference to either std::istream, std::ostream, or std::iostream, when we need a stream which can;read, write, or both, respectively.


( Note: IF it's not obvious: Ivan is an ifstream, Owen an ofstream, and John a fstream. )

like image 169
Filip Roséen - refp Avatar answered Sep 23 '22 14:09

Filip Roséen - refp