2014-10-31 43 views
4

我有一個成員變量,enabled_m,它的值取決於許多變量。由於這些不變量應當由類保持下去,我希望它是private是否可以指定僅用於const操作的公共成員變量public?

class foo_t 
{ 
public: 
    void set_this(...); // may affect enabled_m 
    void set_that(...); // may affect enabled_m 
    void set_the_other_thing(...); // may affect enabled_m 

    bool is_enabled() const { return enabled_m; } 

private: 
    bool enabled_m; 
}; 

其中一期工程,但實際上我的意圖是要求的foo_t用戶通過類去修改enabled_m。如果用戶希望只閱讀enabled_m,這應該是允許的操作:

bool my_enabled = foo.enabled_m; // OK 
foo.enabled_m = my_enabled; // Error: enabled_m is private 

有沒有一種方法,使enabled_mpublicconst操作和private用於非const運營,而不必要求用戶通過訪問器例程?

+5

使用getter函數有什麼問題?如果你關心的是效率問題,那麼返回'const bool&'的'inline'函數可能會編譯成與直接成員訪問相同的內容。 – dlf 2014-10-31 17:15:53

+0

你或許可以創建一些代理對象,指向你的「真正的」布爾 - 但它真的值得嗎?吸氣劑是最流行和最乾淨的解決方案。 – 2014-10-31 17:17:26

+0

除了@ dlf的擔憂之外,我認爲即使可以這樣做,界面二元性也會讓事情變得混亂。 – Borgleader 2014-10-31 17:17:40

回答

9

不,沒有辦法限制僅對會員進行修改。 private限制對名稱的所有訪問; const可以防止到處修改。

有一些怪誕的選擇(如const參考或使用const_cast),但訪問器功能是最簡單和最習慣的方式來做到這一點。如果它是內聯的,就像你的例子那樣,那麼它的使用應該和直接訪問一樣高效。

+0

這也是我的推理路線 - 只是想確定我沒有錯過任何東西。 – fbrereto 2014-10-31 17:20:10

+0

「怪誕」一詞似乎過度優化了一個有效的構造。然而,我認爲最好不要這樣去做,因爲它可能會阻礙這個類的未來發展(f.ex將進行懶惰評估,或者在派生類中做出不同的決定) – Christophe 2014-10-31 18:10:05

+2

@Christophe:添加一個引用成員會破壞副本語義:默認的拷貝構造函數會給你一個對錯誤對象的引用。我會稱之爲怪誕。使用'const_cast'來修改'const'成員是UB,這是無可爭議的怪誕。 – 2014-10-31 18:18:20

10

大多數工程師會偏好使用存取方法,但如果你真的想要,圍繞破解一個,你可以做這樣的事情:

class AccessControl 
{ 
private: 
    int dontModifyMeBro; 
public: 
    const int& rDontModifyMeBro; 
    AccessControl(int theInt): dontModifyMeBro(theInt), rDontModifyMeBro(dontModifyMeBro) 
    {} 

    // The default copy constructor would give a reference to the wrong variable. 
    // Either delete it, or provide a correct version. 
    AccessControl(AccessControl const & other): 
     dontModifyMeBro(other.rDontModifyMeBro), 
     rDontModifyMeBro(dontModifyMeBro) 
    {} 

    // The reference member deletes the default assignment operator. 
    // Either leave it deleted, or provide a correct version. 
    AccessControl & operator=(AccessControl const & other) { 
     dontModifyMeBro = other.dontModifyMeBro; 
    } 
}; 
+2

您需要一個非默認的拷貝構造函數來正確地初始化引用;如果您想允許分配,則使用非默認賦值運算符。 – 2014-10-31 17:24:36

+3

是的,@MikeSeymour,我想這就是爲什麼你把這種方法放在「怪誕」組中。 +1給你的答案。 – iwolf 2014-10-31 17:28:03

5

了大量這裏取決於意圖的背後暴露出啓用狀態,我的一般建議是避免暴露它在所有

通常使用的is_enabled會是這樣的:

if (f.is_enabled()) 
    f.set_this(whatever); 

在我看來,它幾乎總是最好只調用set_this,以及(如果客戶關心)有它返回一個值來表示不管是成功的,所以客戶端代碼變得像:

if (!f.set_this(whatever)) 
    // deal with error 

雖然這可能看起來是一個微不足道的差異,當你開始做多線程編程(一個主要例子)的差異變得absolutel Ÿ關鍵。特別是,測試啓用狀態的第一個代碼,然後嘗試設置該值受競爭條件的影響 - enabled狀態可能會在呼叫is_enabled和呼叫set_this之間發生變化。要長話短說,這通常是一個糟糕的設計。只是不要這樣做。

相關問題