Почему я не могу инициализировать ссылку на `ofstream`/` ifstream`, с экземпляром `fstream`?

Введение

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

У меня есть эти две функции, где нужно читать из файла, а другой должен писать в один.

Все работает с нижеприведенными фрагментами;

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

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

ПРОБЛЕМА

Однако, если я пытаюсь использовать std::fstream, поэтому я могу вызывать обе функции с одним потоком, он не компилируется, а компилятор выдает много сообщений об ошибках.

  • Почему я не могу привязать fstream к ifstream& или 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);
}

Ошибка (ы):


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);

Ответы

Ответ 1

"ДЛИННАЯ ИСТОРИЯ, КРАТКАЯ" - ОТВЕТ

Так как a std::fstream не выводится ни из std::ofstream, ни std::ifstream, ссылка не является "совместимой" с экземпляром std::fstream.

Используйте std::istream& и std::ostream& вместо std::ifstream& и std::ofstream& (соответственно).

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

Введение

Как компилятор пытается вам сказать; std::fstream не наследуется от std::ifstream, поэтому вы не можете инициализировать ссылку на последнюю со значением первого.

Я наткнулся на нескольких разработчиков, которые, по-видимому, полагают, что std::fstream, за кулисами, представляет собой какое-то прямое слияние между std::ifstream и a std::ofstream, и что он реализуется за счет.

Когда их спрашивают, почему они думают, что это так, многие считают, что ответ можно суммировать; "потому что это имеет смысл, правильно?"


АНАЛОГИ SILLY

Представьте, что у нас есть три брата и сестры; Иван, Оуэн и Джон, живущие в семье, где все чтение и письмо.

Все братья родились с подарком;

  • Иван отлично читает и отдал ему всю свою жизнь, он больше ничего не делает и
  • У Оуэна есть вещь для написания, что странно, поскольку он не может читать, и
  • Джону повезло, и у него есть умение читать и писать.

Просто потому, что Джон может делать то и другое, что могут сделать его братья, не означает, что они его родители - они, в конце концов; его братья.

Все трое братьев унаследовали свои определенные черты от других родственников, а не друг от друга.


ОТВЕТ

std::fstream не строится "поверх" std::{i,o}fstream, хотя они разделяют определенные части их отдельного дерева наследования.


iostreams inheritance visualized

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


При принятии потока в общем коде вам не нужно заботиться о "реальном" типе базового потока.

Действительно ли имеет значение, если мы передадим в std:: stringstream, std:: fstream или std:: ofstream нашу функцию, которая записывает некоторые выходные данные в поток? Нет, все, о чем мы заботимся, это способность читать/писать.

Мы выражаем это, создавая ссылку на std::istream, std::ostream или std::iostream, когда нам нужен поток, который может, читать, писать или и то, и другое соответственно.


( Примечание: ЕСЛИ это не очевидно: Иван - это ifstream, Owen thestream и John fstream.)