0

コメントやその他の不要なデータを自動的に削除するカスタム入力ファイル ストリームを作成したいと考えています。私は次の解決策を思いつきました:

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メソッドを含むインターフェースもありますSerialize/Deserialize。私にはすべてがうまく見えます。

しかし、私は決して継承してはならず、std::ifstreamcustom を作成する必要があることを読みましたstd::streambuf

なぜ継承するのが悪いのか、コメントやその他のデータを同様に無視std::ifstreamするカスタムを作成するにはどうすればよいか説明していただけますか?std::streambuf

4

3 に答える 3

4

クラスがどのように機能することを期待しているかは、私にはわかりません。operator>>では関数は仮想ではなく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 );
        }
    }
};

他のタイプのコメントを処理する必要がある場合、または引用符で囲まれたコメント文字について心配する場合は、さらにロジックが必要になります (複数の文字のシーケンスをテストするために、文字を収集するためのプライベート バッファーを使用する可能性があります)。

于 2014-04-24T13:27:59.223 に答える
3

の動作を変更するためにパブリックに継承すると、ifstream意図しない結果につながるためistream、多くの場合、それはまだであり、そのように扱われるため、カスタムの動作を取り除きます。

  • FileReaderを期待する関数に渡す場合::std::istream&、カスタム機能は使用されません

  • C演算子のようなクラスはtemplate<typename T> T& operator>>(T& in, C& target);使用できません

  • 基礎となる機能がistream直接使用されると、ラッパー関数は機能しません

あなたの場合、ifstreamメンバーとして持つように切り替えるか、その継承を非公開に変更するだけです。

于 2014-04-24T13:28:27.597 に答える
1

これは基本的std::iostreamにカスタマイズする設計std::streambufであり、コンテキスト固有のすべての機能が存在する場所です。

于 2014-04-24T13:26:18.977 に答える