Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么不从ifstream继承_C++_Stream_Ifstream_Streambuf - Fatal编程技术网

C++ 为什么不从ifstream继承

C++ 为什么不从ifstream继承,c++,stream,ifstream,streambuf,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 IsBaseOfSerializabl

我想创建一个自定义的输入文件流,它可以自动删除注释和其他垃圾数据。我提出了以下解决方案:

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() {... }
};
我还有一个接口ISerializable,其中包含序列化/反序列化方法。我觉得一切都很好

但我已经读到,我不应该从std::ifstream继承,而应该创建自定义std::streambuf


您能解释一下为什么从std::ifstream继承是不好的,我如何创建自定义std::streambuf,它以类似的方式忽略注释和其他数据?

基本上是std::iostream设计来定制std::streambuf,这就是所有特定于上下文的功能所在。

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

通常的做法是提供一个过滤 streambuf,用于过滤输入文本。例如,如果 注释从a到行的末尾,而您没有 不得不担心引用之类的事情,比如 以下将起作用:

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 );
        }
    }
};
如果你需要处理其他类型的评论,或者担心 引用注释字符,您可能需要更具逻辑性 用于收集字符的专用缓冲区,用于测试
一个以上字符的序列

因为公开继承以修改ifstream的行为将导致意外的后果,因为它仍然是一个istream,在许多情况下都会被视为istream-剥离您的自定义行为:

将FileReader传递给需要::std::istream&的函数时,将不使用自定义功能

具有模板T&operator>>T&in、C&target等运算符的任何C类;将无法使用

无论何时直接使用底层istream的任何功能,包装器函数都不起作用

在您的情况下,您可以简单地切换到将ifstream作为成员,或者将其继承更改为private