从streambuf派生而不重写相应的流

时间:2010-06-07 12:42:38

标签: c++ stream fstream mmap streambuf

前几天,我决定编写一个使用streambuf和预读的mmap子类会很有趣。 我查看了我的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导向的

我无法理解的是:为什么fstreamfilebuf紧密耦合,因此除了filebuf之外不能使用任何其他内容分离流和bufs的全部意义在于可以使用具有不同缓冲区的流。

解决方案:

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

=> filebuf应该是一个纯虚拟类,没有任何其他属性。因此,人们可以从中继承而不携带其所有的FILE *垃圾。

您对此主题的看法?

4 个答案:

答案 0 :(得分:11)

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

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

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

回答你的问题:文件流和文件缓冲区的连接非常紧密,因为前者仅用于简化后者的创建。使用文件流可以轻松设置所有内容 使用您自己的流类来包装自己的流缓冲区的构造应该不是问题,因为您不应该传递文件流,而只是(引用)基类。

答案 1 :(得分:2)

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

从某种意义上说,你写的有关模板解决方案的内容是可以的。但是basic_stream也可以导出为tcp_stream。在这种情况下,fstream的构造函数有点无用。因此,您需要提供一个新的tcpstream类,继承自basic_stream的正确参数,以便构造函数能够创建tcp_stream。最后,您不会使用fstream中的任何内容。创建这个新的tcpstream只需编写3或4个函数。

最后,您将从fstream类派生而没有任何真正的理由。这将在类层次结构中添加更多耦合,不需要耦合。

答案 2 :(得分:2)

查看mapped_file库中的Boost.Iostreams。我自己从未使用它,但似乎它已经可以做你需要的了。

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

答案 3 :(得分:1)

std::fstream的重点是_ {strong> F _ile基于std::stream。如果您想要std::stream支持的普通mmstreambuf,则应创建mmstreambuf并将其传递给std::stream::stream(std::streambuf*)