为什么我不能用`fstream`的实例来初始化对`ofstream`或`ifstream`的引用?

16

介绍

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:在函数‘int main()’中:
foo.cpp:9:16: 错误:无效的初始化类型引用‘std::ifstream& {aka std::basic_ifstream<char>&}’,从表达式类型 ‘std::fstream {aka std::basic_fstream<char>}’ read_foo (fs);
^
foo.cpp:3:7: 注意:正在传递参数 1 给‘void read_foo(std::ifstream&)’ void read_foo (std::ifstream& out);


foo.cpp:10:16: 错误:无效的初始化类型引用‘std::ofstream& {aka std::basic_ofstream<char>&}’,从表达式类型 ‘std::fstream {aka std::basic_fstream<char>}’
write_foo (fs);
^
foo.cpp:4:6: 注意:正在传递参数 1 给‘void write_foo(std::ofstream&)’ void write_foo (std::ofstream& out);


1
那些给这个问题点踩的人,为什么认为这个问题值得-1分? - Filip Roséen - refp
1个回答

27

"长话短说" - 答案

由于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::ifstreamstd::ofstream之间的直接合并,并且是通过从两者中派生实现的。

当被问及为什么他们这样认为时,很多人认为答案可以归结为:"因为这很有道理,对吧?"


愚蠢的类比

想象一下我们有三个兄弟姐妹:IvanOwenJohn,他们生活在一个阅读和写作至上的家庭中。

所有兄弟都天生拥有一项天赋;

  • Ivan擅长阅读,并将其全部生命献给了阅读,他从不做其他事情;
  • Owen喜欢写作,这很奇怪,因为他不会阅读;
  • John很幸运,拥有了阅读和写作的技能。

仅仅因为John能够做到他的兄弟们所能做到的两件事,并不意味着他们是他的父母-毕竟,他们只是他的兄弟。

所有三个兄弟都从其他亲戚那里继承了自己的某些特质,而不是从彼此那里继承。


答案

std::fstream并非构建在std::{i,o}fstream之上,尽管它们共享各自继承树的某些部分。


iostreams inheritance visualized

srchttp://en.cppreference.com/w/cpp/io


在通用代码中接受流时,您不应该关心底层流的"真实"类型。

如果我们将std::stringstreamstd::fstreamstd::ofstream传递到写一些输出数据到stream的函数中,这真的很重要吗?不,我们关心的只是能够读/写的能力。

当我们需要一个既能读取又能写入的流时,我们通过引用std::istreamstd::ostreamstd::iostream来表达这一点,分别表示;读取写入读取/写入


注意:如果不明显:IvanifstreamOwenofstream


3
好的解释,并且它展示了面向对象编程的局限性。(使用模板,代码将能够工作,因为fstream提供了ifstreamofstream两个类的方法。) - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接