c++ - 为什么不继承ifstream

标签 c++ stream ifstream streambuf

我想创建一个自定义输入文件流,自动去除评论和其他垃圾数据。我提出了以下解决方案:

class FileReader : public std::ifstream
{
public:
  explicit FileReader(const char* fName) { open(fName); }

  ~FileReader() { if (is_open()) close(); }

  template <typename T, bool IsBaseOfSerializable>
  struct DoRead
  {
    void operator()(std::ifstream& ifs, T& data) { ifs >> data; }
  };

  template <typename T>
  struct DoRead<T, true>
  {
    void operator()(FileReader& reader, T& data) { data.Deserialize(reader); }
  };

  template <typename T>
  friend FileReader& operator>>(FileReader& reader, T& data)
  {
    reader.SkipCommentsAndGarbage();
    DoRead<T, std::is_base_of<ISerializable, T>::value> doread;
    doread(reader, data);
    return reader;
  }

  void SkipCommentsAndGarbage() {... }
};

我还有接口(interface) ISerializable 包含 Serialize/Deserialize 方法。我觉得一切都很好。

但我读到我永远不应该继承 std::ifstream 并且应该创建自定义 std::streambuf

你能解释一下为什么从 std::ifstream 继承是不好的吗?我如何创建自定义的 std::streambuf 来忽略注释和类似的其他数据怎么办?

最佳答案

我不清楚您希望您的类(class)如何运作。这 operator>> 函数在 std::istream不是虚函数,并且 迟早(通常更快,在编写良好的代码中),你会 以 std::istream& 结尾。你是转发的想法可以 在某些情况下使用,但在这种情况下,您不会继承自 std::ifstream;你包含一个指向 istream 的指针,并且 转发给它。 (通过不继承,你确保你不能 以 istream& 结尾。这是有限的,但可以接受 某些情况。)

通常的做法是提供一个过滤 streambuf,过滤输入文本。例如,如果 注释是从 # 到行尾,而你不需要 不得不担心报价之类的,像 以下将起作用:

class UncommentStreambuf : public std::streambuf
{
    std::streambuf* mySource;
    std::istream*   myOwner;
    char            myBuffer;
protected:
    int underflow() override
    {
        int results = mySource->sbumpc();
        if ( results == '#' ) {
            while ( mySource->sgetc() != '\n' ) {
                mySource->sbumpc();
            }
        }
        if (results != traits_type::eof()) {
            myBuffer = results;
            setg( &myBuffer, &myBuffer, &myBuffer + 1 );
        } else {
            setg( nullptr, nullptr, nullptr );
        }
        return results;
    }
public:
    UncommentStreambuf( std::streambuf* source )
        : mySource( source )
        , myOwner( nullptr )
    {
    }
    UncommentStreambuf( std::istream& source )
        : mySource( source.rdbuf() )
        , myOwner( &source )
    {
        source.rdbuf( this );
    }
    ~UncommentStreambuf()
    {
        if ( myOwner != nullptr ) {
            myOwner->rdbuf( mySource );
        }
    }
};

如果你需要处理其他类型的评论,或者担心 引用注释字符,你需要更多的逻辑(可能 一个用于收集字符的专用缓冲区,以便测试 一个以上字符的序列)。

关于c++ - 为什么不继承ifstream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23270176/

相关文章:

通过套接字进行 C# 序列化,一个类正在序列化,另一个类没有

java - 找出流中有多少字节的更好方法?

c++ - 想要在 istream C++ 的行尾读取重要的 double 值

c++ - 向 C++ 结构添加新成员并向后兼容

c++ - C'tor 的类型转换不起作用

c++ - 当我将类作为模板时,为什么会编译?

c# - 如何将大文本文件拆分为较小的文件?

c++ - 基于范围的for循环的奇怪问题

c++ - ifstream::read 不起作用?

c++ - Linux 上的 file.open() 无法打开我的文件,如何解决?