2014-04-24 103 views
0

我想創建一個自動刪除註釋和其他垃圾數據的自定義輸入文件流。我想出了以下解決方案:爲什麼不從ifstream繼承

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() {... } 
}; 

我也有含Serialize/Deserialize方法接口ISerializable。一切看起來都很好。

但我讀過,我不應該從std::ifstream繼承,並應該創建自定義std::streambuf

您能否解釋爲什麼從std::ifstream繼承不好,以及如何創建自定義std::streambuf,以類似的方式忽略註釋和其他數據?

回答

3

我不清楚你期望你的班級如何工作。該 operator>>功能虛擬的std::istream和 遲早(通常更早,在寫得很好的代碼),你會 結束了一個std::istream&。在某些情況下,您可以使用 ,但在這種情況下,您不會繼承 std::ifstream;你包含一個指向istream和 的指針。 (如果不繼承,可以確保你不能 結束了一個istream&。這是限制,但可以接受在 某些情況下)。

這樣做的正常方式是提供一個過濾 流緩衝,這過濾輸入文本。例如,如果 評論是從#到該行的結束,而你沒有 擔心報價和等,一些簡單的 下面的工作:

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); 
     } 
    } 
}; 

如果您需要處理其他類型的註釋,或擔心 引用註釋字符,你需要更多的邏輯(與可能 專用緩衝器收集字符,以測試 多個字符的序列)。

1

它基本上是std::iostream設計來定製std::streambuf,這是所有上下文特定功能駐留的地方。

2

因爲公開繼承修改的ifstream行爲會導致意想不到的後果,因爲它仍然是一個istream在很多情況下會被視爲這樣 - 剝了你的自定義行爲:

  • 經過時FileReader給需要::std::istream&功能,您的自定義功能將無法使用

  • 任何類C與像template<typename T> T& operator>>(T& in, C& target);運營商將無法使用

  • 每當底層istream的任何功能,直接使用,您的包裝功能不起作用

在你的情況,你可以簡單地切換到有你ifstream作爲成員或改變其遺傳給私人。