2015-08-09 50 views
3

通過聲明一個成員私人,非朋友功能不能直接訪問該成員。但有一種方法可以通過使用指針的類型來訪問它們,例如:防止程序員使用任何技巧訪問私人類成員

class Foo { 

    private: 
    int value; 

    public: 
    inline int get() { 
     return value; 
    } 
    inline Foo (int value) { 
     Foo::value = value; 
    } 

} foo(1234); 

int main() { 
    using namespace std; 
    cout << foo.display() << endl; // display 1234 
    int *p = (int *)(&foo); // HERE! 
    *p = 5678; 
    cout << foo.display() << endl; // display 5678, foo.value has been changed 
    return 0; 
} 

我們是否可以阻止用戶使用這些技巧?或者我們可以禁止將Foo *轉換爲int *

+5

簡答:你不能。 –

+4

你的代碼有*未定義的行爲*順便說一句。 – juanchopanza

+0

@juanchopanza我的編譯器 - GCC編譯沒有任何警告和錯誤。 – DMaster

回答

4

嗯,不可能阻止確定的程序員進行明確的類型轉換,因爲確定的程序員可以運用的方法幾乎是無限的 - 特別是如果願意接受未定義的行爲。

從哲學上講,C++類型系統通常設計爲使事故難以發生。但是,它的目的不是爲了防止程序員故意顛覆類型系統。

通過使用技術組合可以使事情變得更加困難;

  1. 採用PIMPL方法(由parapura拉庫瑪在應答已經提到)
  2. 介紹的偏移成員(包括平普爾的)。例如,對於程序員來說,實現細節可能會被偏移18個字節並不一定是顯而易見的。
  3. 爲您的課程提供私人operator&(),這將會阻止使用&object來獲取對象的地址。
  4. 不提供返回this的成員函數,並且不返回任何專用或受保護的類數據的地址(或引用)。並沒有公開的數據。

但事情是,一個足夠堅定的程序員會找到一種方法來解決像這樣的各種技巧,即使沒有訪問源代碼。這些技巧也會讓開發者更難以使用你想要的更平常的方式來使用你的課程。

+0

您的回答非常有用,謝謝。我們不能欺騙指針的類型轉換,但我們可以禁止獲取對象的地址。問題是,通過將'Foo'類型的對象聲明爲自定義類的成員(例如'Bar',它不禁止獲取其地址),用戶可以通過強制轉換來訪問'Foo :: value' 'Bar *'到'int *'。現在,我認爲真的沒有辦法! – DMaster

+0

另外,添加額外的成員來複制信息並檢查內部一致性。添加額外的虛擬成員,應該修改... – Jarod42

+1

*「我們不能欺騙指針的類型轉換,但我們可以禁止獲取對象的地址。」*如何?有http://en.cppreference.com/w/cpp/memory/addressof –

2

一種選擇是使用PIMPL成語,並且從不包含實現類標題作爲庫的一部分。

class A 
{ 
    Aimpl* a_; 
public: 
    int getValue(); 
}; 

現在用戶可以訪問但永遠不知道Aimpl的內部修改它。

+2

這不應該是'Aimpl * a_'嗎?它也不會阻止某人如果想要改變價值,那隻會讓它變得更加困難。 – Adam

+0

我同意@Adam,人們可以訪問'a_',因此可以訪問'a_'指向的地方。 – DMaster

0

您無法阻止任何人在您顯示時編寫看起來合法有效的代碼。

似乎是因爲

*p = 5678; 

實際上是不確定的行爲,並且不能在給予相同的結果你的依賴。