2012-10-06 35 views
0

我不知道下列語法是否可以被「承認」,或者如果良好實踐認爲這是來自地獄。目標是增加一定程度的保護,迫使開發人員充分意識到自己在做什麼。下面是語法:安全地直接訪問班級成員

class MyClass 
{ 
    public: 
     template<bool RemoveProtection = false> 
     inline std::ofstream& writeStream() 
     { 
      static_assert(RemoveProtection, "You're doing it wrong"); 
      return _writeStream; 
     } 

     inline const std::ofstream& writeStream() const 
     { 
      return _writeStream; 
     } 

    protected: 
     std::ofstream _writeStream; 
}; 

的用途是:

x.writeStream().good(); // <- OK 
x.writeStream().put('c'); // <- NOT OK 
x.writeStream<true>().put('c'); // <- OK 

,我覺得這是一個便捷的方式告訴給開發者:「當心,你使用的是低層次的功能和你必須小心你正在做的事情「。這是一種「可接受」的方式,提供一種「保護」的直接訪問類成員?有沒有其他的方式來編碼這樣的事情?

+8

你讓你的代碼變得醜陋,難以維護和不方便......究竟是什麼?定義你的界面。這是你班級的接口。不要讓開發人員通過使用一些荒謬的模板標記hackery來繞過它。如果你正在編寫代碼,你總是必須知道你在做什麼。必須明確鍵入''來表明你*特別*知道你在做什麼,只是......非常非常錯誤的原因。開發人員有文檔。他們不需要訓練輪和人爲限制,他們需要清晰簡潔的代碼,讓他們完成任務。 – meagar

回答

2

看一看meagar's comment

你讓你的代碼醜陋,難以維護和不方便......究竟是什麼?定義你的界面。這是你班級的接口。不要讓開發人員通過使用一些荒謬的模板標記hackery來繞過它。如果你正在編寫代碼,你總是必須知道你在做什麼。不得不明確鍵入<true>來表明你特別知道你在做什麼,只是...非常非常錯誤的方向。開發人員有文檔。他們不需要訓練輪和人爲限制,他們需要清晰簡潔的代碼,讓他們完成任務。 - meagar 2012-10-06 02:41:53Z

您提供給其他人的類別在其他用戶使用它時應永遠無法進入不可預知的狀態。在這種情況下,一個不可預測的狀態是你在寫課程時從未考慮過的狀態。因此,您應該要麼永遠不允許訪問到您的類的低級方法或文檔可能的缺陷

比方說,你正在寫一個記錄:

struct MyLogger{ 
    MyLogger(std::string filename) : stream(filename.c_str()){}  
    template <typename T> 
    MyLogger& operator<<(const T& v){ stream << v << " "; return *this;} 

private: 
    std::ofstream stream; 
}; 

忽略不存在一個拷貝構造函數和賦值操作數丟失。還要忽略它是一個粗略的記錄器,它甚至不提供時間戳。但是,如您所見,記錄器的狀態完全取決於記錄器的方法,例如,如果文件已成功打開,它將不會關閉,直到記錄器被破壞。

現在說,我們用你的方法:

struct MyLogger{ 
    MyLogger(std::string filename) : stream(filename.c_str()){} 
    template <typename T> 
    MyLogger& operator<<(const T& v){ stream << v << " "; return *this;} 

    template<bool RemoveProtection = false> 
    inline std::ofstream& writeStream() 
    { 
     static_assert(RemoveProtection, "You're doing it wrong"); 
     return stream; 
    } 

    inline const std::ofstream& writeStream() const 
    { 
     return stream; 
    } 

private: 
    std::ofstream stream; 
}; 

現在有人使用下面的代碼

logger.writeStream<true>.close(); 

爆炸。你的記錄器壞了。當然這是用戶的錯,因爲他們使用了<true>,不是嗎?但是用戶往往會複製示例代碼,特別是如果他第一次使用庫。用戶看到你的例子

logger.writeStream().good(); // <- OK 
logger.writeStream().put('c'); // <- NOT OK 
logger.writeStream<true>().put('c'); // <- OK 

並且首先完全忽略文檔。然後,他將使用第一個和最後一個版本。後來他發現最後一個版本每次都工作!多麼神奇的東西<true>是。然後,他開始責怪你這種情況發生邪惡的東西,所以你必須保護自己免受公然火焰與文檔,其中包括一個警告:

/** 
    * \brief Returns a reference to the internal write stream 
    * 
    * \note You have to use the template parameter `<true>` in order to use it 
    * 
    * \warning Please note that this will return a reference to the internal 
    *   write stream. As such you shouldn't create any state in which 
    *   the logger cannot work, such as closing the stream.   
    */ 
    template<bool RemoveProtection = false> 
    inline std::ofstream& writeStream() 
    { 
     static_assert(RemoveProtection, "You're doing it wrong"); 
     return stream; 
    } 

那麼,爲什麼我們得到什麼?我們仍然必須在某個地方發出警告。

struct MyLogger{ 
    MyLogger(std::string filename) : stream(filename.c_str()){} 
    template <typename T> 
    MyLogger& operator<<(const T& v){ stream << v << " "; return *this;} 

    /** 
    * The internal write stream. Please look out that you don't create 
    * any state in which the logger cannot work, such as closing the stream. 
    */ 
    std::ofstream stream; 
}; 

或粘連,

/** >put warning here< */ 
inline std::ofstream & writeStream() 
{ 
    return stream; 
} 

Woops:如果我們做了stream公開這本來是簡單得多。因此,要麼不允許訪問你的低級方法(如果允許使用它們的話,建立一個包裝到特定的std::ofstream方法),或者記錄可能發生的缺陷,如果你改變對象的內部很多東西,不要走中間路線,用static_assert看起來沒問題。

+0

非常好的解釋!非常感謝你 ! – Vincent