關鍵是protected
授予您訪問您自己的副本的成員,而不是的任何其他對象的成員。這是一個常見的誤解,因爲更多的情況下,我們總結並指出protected
授予對派生類型成員的訪問權限(沒有明確說明只對自己的基地...)
現在,這是一個原因,並且通常不應該訪問層次結構的不同分支中的成員,因爲您可能會破壞其他對象所依賴的不變量。考慮到在該緩存以下不同的策略的結果一些大的數據成員(受保護的)和兩個派生類型執行一個昂貴的計算類型:
class base {
protected:
LargeData data;
// ...
public:
virtual int result() const; // expensive calculation
virtual void modify(); // modifies data
};
class cache_on_read : base {
private:
mutable bool cached;
mutable int cache_value;
// ...
virtual int result() const {
if (cached) return cache_value;
cache_value = base::result();
cached = true;
}
virtual void modify() {
cached = false;
base::modify();
}
};
class cache_on_write : base {
int result_value;
virtual int result() const {
return result_value;
}
virtual void modify() {
base::modify();
result_value = base::result();
}
};
的cache_on_read
型捕獲修改對數據和標記結果爲無效,以便下一次讀取的值重新計算。如果寫入次數相對較高,這是一個很好的方法,因爲我們只根據需求執行計算(即多次修改不會觸發重新計算)。 cache_on_write
預先預先計算出結果,如果寫入次數很少,並且您希望讀取的確定性成本(認爲讀取延遲較低),則這可能是一種很好的策略。
現在回到原來的問題。兩種緩存策略都保持比基本更嚴格的不變量集合。在第一種情況下,如果data
在上次讀取後未被修改,則額外不變量爲cached
爲true
。在第二種情況下,額外的不變量是result_value
是操作在任何時候的值。
如果第三個派生類型引用base
並訪問data
來編寫(如果protected
允許),那麼它將與派生類型的不變量斷開。
這就是說,語言的規範是破碎(個人意見),因爲它留下後門來實現該特定結果。特別是,如果在派生類型中創建指向基元成員的指針,則會在derived
中檢查訪問權限,但返回的指針是指向成員base
的指針,該指針可應用於任意base
對象:
class base {
protected:
int x;
};
struct derived : base {
static void modify(base& b) {
// b.x = 5; // error!
b.*(&derived::x) = 5; // allowed ?!?!?!
}
}
@iammilind你確定你正在關閉正確的問題嗎?或者它應該是另一種方式? – Eiko 2016-08-02 13:24:38
@Eiko最初我先關閉了另一個。然後我發現現在的答案比標準更詳細和引用。因此重新開放並關閉了這個。 – iammilind 2016-08-02 14:09:29