【问题标题】:Deriving from streambuf without rewriting a corresponding stream从 streambuf 派生而不重写相应的流
【发布时间】:2010-06-07 12:42:38
【问题描述】:

几天前,我决定编写一个使用mmap 并预读的streambuf 子类会很有趣。 我查看了我的 STL (SGI) 如何实现 filebuf 并意识到 basic_filebuf 包含 FILE*。所以从basic_filebuf继承是不可能的。

所以我继承自basic_streambuf。然后我想将我的mmapbuf 绑定到一个 fstream。

我认为我唯一需要做的就是复制 filebuf... 的隐式接口...但这是一个明显的错误。在 SGI 中,basic_fstream 拥有一个 basic_filebuf。无论我调用basic_filestream.std::::ios::rdbuf( streambuf* ),文件流都会完全忽略它并使用自己的filebuf。

所以现在我有点困惑......当然,我可以创建自己的 mmfstream,这将是 fstream 的精确复制/粘贴,但这听起来真的不是面向 DRY。

我无法理解的是:为什么fstream 与filebuf 耦合得如此紧密,以至于除了filebuf 之外就无法使用其他任何东西?分离流和缓冲区的重点是可以使用具有不同缓冲区的流。

解决方案:

=> filestream 应该依赖于 filebuf 的隐式接口。也就是说,fstream 应该由 streambuf 类模板化。这将允许每个人都为fstream 提供自己的streambuf 子类,只要它实现filebuf 的隐式接口。问题:我们无法向fstream 添加模板参数,因为在使用fstream 作为模板模板参数时会破坏模板选择器。

=> filebuf 应该是一个没有任何附加属性的纯虚拟类。这样就可以继承它而不携带它所有的 FILE* 垃圾。

你对这个主题的想法?

【问题讨论】:

  • 你的题目有错字;流错误 => 流缓冲区。不知道你的问题的答案,对不起!

标签: c++ stream fstream mmap streambuf


【解决方案1】:

在 IO 流的设计中,大多数实际流的功能(与流缓冲区的功能相反)是在 std::basic_istream、std::basic_ostream 及其基类中实现的。 字符串和文件流类或多或少只是方便的包装器,它们确保实例化具有正确类型缓冲区的流。

如果您想扩展流,您几乎总是希望提供自己的流缓冲区类,而您几乎不需要提供自己的流类。 .

一旦你有了自己的流缓冲区类型,你就可以让它成为你碰巧拥有的任何流对象的缓冲区。或者您从 std::basic_istream、std::basic_ostream 和 std::basic_iostream 派生您自己的类,它们会实例化您的流缓冲区并将其传递给它们的基类。
后者对用户来说更方便,但需要您为缓冲区的实例化编写一些样板代码(即流类的构造函数)。

回答您的问题:文件流和文件缓冲区耦合得如此紧密,因为前者的存在只是为了简化后者的创建。使用文件流可以轻松进行所有设置。
使用您自己的流类来包装您自己的流缓冲区的构造应该不是问题,因为无论如何您都不应该传递文件流,而只是(引用)基类。

【讨论】:

  • 因为您没有回答问题。此处所写的任何内容均无助于解决问题。这就像你在自言自语,回答一个想象中的“iostream 和 streambuf 有什么区别”的问题......
  • @Aurélien:公平点,但我确实打算回答你的问题。我试图改变答案,让这变得更加明显。
  • @Aurélien:谢谢你这样做。
【解决方案2】:

查看Boost.Iostreams 库中的mapped_file。我自己从未使用过它,但它似乎已经可以满足您的需求。

编辑:哎呀,重新阅读您的问题,我看到您这样做是为了好玩。或许您可以从 Boost.Iostreams 中汲取灵感?

【讨论】:

  • 是的,今天早上我和一位同事聊天,他也告诉我 boost 已经有了 :) 但正如你所注意到的,这主要是为了好玩!谢谢。
【解决方案3】:

fstream 本身并不是一个大类。它继承自basic_stream,以提供对所有<< 和>> 操作的支持,包含一个必须初始化的专用steambuf,以及将参数传递给streambuf 构造函数的相应构造函数。

从某种意义上说,您所写的有关模板化解决方案的内容是可以的。但是basic_stream 也可以派生为tcp_stream,例如。在那种情况下,fstream 的构造函数就有点没用了。因此,您需要提供一个新的tcpstream 类,该类继承自basic_stream,并带有正确的参数,以便构造函数能够创建tcp_stream。最后,您不会使用来自fstream 的任何东西。创建这个新的tcpstream 只需编写 3 或 4 个函数。

最后,您将毫无理由地从 fstream 类派生。这会在类层次结构中增加更多的耦合,不需要耦合。

【讨论】:

  • 我完全同意 tcp_stream 的说法,因为 tcp 流不能像文件流或字符串流那样被操纵。但是在这里,我们说的是应该以完全相同的方式访问的两个流缓冲区:它们都操作文件,并且都应该被文件流访问。如果你不能在没有另一个的情况下使用一个,那么在不同的类中使用 fstream 和 filebuf 有什么意义?
  • 我很确定您需要为新的streambuf 提供额外的参数(比给filebuf 的参数更多)。因此,您必须为新的filestream 编写新的构造函数。这些构造函数是您唯一需要编写、创建它的东西,无论是通过派生还是独立。
  • > 不,我必须实现所有 fstream 附加功能:open、close、is_open,... 而且,问题不在于编写这些小方法,它只是我不应该有去做吧。这将是复制/粘贴,没有代码重用。更重要的是,我的用户必须从 fstream 切换到 mmfstream,这是不应该的。
  • 因为你可以在没有一个的情况下使用另一个!
  • @sbi:公平点,没有那样读。已删除评论和反对票。
【解决方案4】:

std::fstream 的全部意义在于它是一个基于_F_ile 的std::stream。如果你想要一个由mmstreambuf 支持的普通std::stream,那么你应该创建一个mmstreambuf 并将其传递给std::stream::stream(std::streambuf*)

【讨论】:

  • "std::fstream 的全部意义在于它是一个基于 _F_ile 的 std::stream" > 我想要一个基于文件的流!我的mmstreambuf 类提供与filebuf 完全相同的功能,但使用映射内存而不是缓冲内存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 1970-01-01
  • 1970-01-01
  • 2017-05-04
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
相关资源
最近更新 更多