前几天,我决定编写一个使用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导向的
我无法理解的是:为什么fstream
与filebuf
紧密耦合,因此除了filebuf
之外不能使用任何其他内容分离流和bufs的全部意义在于可以使用具有不同缓冲区的流。
解决方案:
=> filestream
应该依赖filebuf
的隐式接口。也就是说,fstream应该由streambuf类进行模板化。只要它实现fstream
的隐式接口,这将允许每个人为filebuf
提供自己的streambuf子类。问题:我们无法将模板参数添加到fstream
,因为它会在使用fstream
作为模板模板参数时中断模板选择器。
=> filebuf
应该是一个纯虚拟类,没有任何其他属性。因此,人们可以从中继承而不携带其所有的FILE *垃圾。
您对此主题的看法?
答案 0 :(得分:11)
在IO流的设计中,大多数实际流的功能(与流缓冲区的功能相反)在std::basic_istream
,std::basic_ostream
及其基类中实现。 字符串和文件流类或多或少只是便利包装器,它确保实例化具有正确类型缓冲区的流。
如果您想扩展流,您几乎总是希望提供自己的流缓冲类 ,而您几乎不需要提供自己的流类。 。
一旦拥有了自己的流缓冲区类型,就可以将它作为碰巧遇到的任何流对象的缓冲区。或者从std::basic_istream
,std::basic_ostream
和std::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*)