2012-09-03 37 views
1

問題:如何使它成爲一個const引用公開返回並且非const引用是私人返回的?

我正在嘗試爲我的類中的某些變量創建一個只讀模板。這涉及一個模板類,它在公開時返回一個對數據的const引用。然而,在類中,我需要對數據進行操作,所以我試圖返回一個非const私有引用。這裏的基本知識:C++ - 使用模板公開返回一個const引用和一個非const引用私人

private: operator T&() { return data; } 
public: operator const T&() const { return data; } 

當我添加非const引用如上圖所示,如果我嘗試公開訪問變量我的Visual Studio 2010中cl.exe時編譯器告訴我,它不能訪問私有成員在類。如果使用模板聲明x,那麼簡單的cout << myobj.x << endl將會失敗。

error C2248: 'proxy<T,C>::operator int &' : cannot access private member declared in class 'proxy<T,C>' 

這裏是參考其他線程:
C++ - How to make read only class member variables in Visual Studio 2010 - Stack Overflow

編輯: 你問的代碼,所以在這兒呢。

template <class T, class C> 
class proxy { 
    friend C; 
private: 
    T data; 
    T operator=(const T& arg) { data = arg; return data; } 
    operator T&() { return data; } // I'd expect this is only returned privately 
public: 
    operator const T&() const { return data; } 
}; 

class myClass { 
public: 
    proxy<int,myClass> x; 

    void f(int i) { 
     x = i; 
    } 
}; 

int main(int argc, char **argv) 
{ 
    myClass test; 
    test.f(12); 
    cout << test.x << endl; // Compiler error trying to access non-const T& 
    return 0; 
} 
+3

聳肩。 'operatorT&'是私有的,所以有一些你沒有顯示的代碼試圖使用它。請發佈足夠詳細的最小代碼以編譯並顯示錯誤。 –

+0

'myobj'被聲明爲'const myclass myobj',對吧? – dasblinkenlight

+3

這不起作用。 'myobj'爲常量時使用'const'版本。否則使用非const的運算符。在選擇操作員時,公開或私人並不重要。之後檢查訪問。 –

回答

0

test不是常量,test.x不是const的,所以myClass::operator int()是一個更好的匹配myClass::operator int() const

訪問控制(私有/公共)不進入它。

2

其實,知名度無障礙環境在C無關的事情++:

  • 能見度規則說,解決超載時所有的成員函數被考慮。
  • 可訪問性意味着如果所選的重載函數不能從所使用的上下文訪問(例如,來自類之外的私有成員),則會發生編譯器錯誤。

有人認爲私人會員不會參與重載決議,如果該職能是在班級外召來的,但事實並非如此。所有功能,無論訪問權限,都會被考慮。

關於你的具體問題,你這樣做:

std::cout << test.x; 

這裏test是非常量,所以是test.x,和兩個過載轉換函數,非const一個選擇。但是,唉,這個函數是私有的,因此編譯器錯誤。

快速的解決辦法是做一個const_cast

std::cout << const_cast<const myClass&>(test).x; 

或者如果你喜歡:

const myClass &ctest = test; 
std::cout << ctest.x; 

正確的解決辦法是隻刪除非const私人之一。您不需要它,因爲從課程上下文中,您可以直接使用data成員。

坦率地說,它看起來像你正在嘗試使用其他語言的語法在C++中實現屬性。屬性很好,但這不是C++的方式。

我的建議是:不要對抗語言,接受它的語法,只是做括號。或者如果x不具有不變性,只是公開。

最短的方法是這樣的:

class myClass { 
private: 
    int _x; 
public: 
    int x() const { 
     return _x; 
    } 
    //if needed 
    void x(int value) { 
     _x = value; 
    } 
}; 

,將在未來的閱讀你的代碼的人(請注意,這可能是我的!),將極大地認識到,你不要試圖重塑語言。

+0

謝謝。你不認爲有什麼方法可以在C++中實現我想要的功能?基本上我想在課堂外寫doSomething(test.x),並在課堂上寫doSomething(x)。在任何一種情況下,x都被稱爲x,而不是_x或getX()等。 – loop

+0

我可以想到兩種方法:1)編寫兩個版本的'doSomething',一個需要'pub ',一個需要'priv '並且讓'x'有一個公共轉換操作符到'pub '和一個私有''priv '; 2)公開'x'! – rodrigo

+0

@rodrigo:'x'已公開。 –

1

在C++中,訪問檢查在重載解析後完成。這與其他可能性相比具有優點和缺點 - 從候選集中刪除不可訪問的功能。

通常解決方案是爲私有函數使用不同的名稱。但看起來你試圖符合你所熟悉的某些功能所需的特定界面。我認爲這不是一個簡單的解決方法。在一般情況下,私有繼承不會起作用,因爲繼承的函數不是候選集的一部分,它們被派生類中的函數隱藏。但是轉換函數是繼承的......並且在測試之後,似乎原始問題再次出現(即使在私有基類中發現了私有轉換)。

所以最後建議使用一個命名的功能,而不是一個轉換的,如:

template <typename T, typename C> 
class proxy 
{ 
    friend C; 
private: 
    T data; 
    T operator=(const T& arg) { data = arg; return data; } 
    T& mutate() { return data; } 
public: 
    operator const T&() const { return data; } 
}; 

class myClass 
{ 
public: 
    proxy<int,myClass> x; 

    void f(int i) 
    { 
     x.mutate() = i; 
    } 
}; 
+0

謝謝本。我正在尋找一些可以在課堂外寫doSomething(test.x),並在課堂內部完成doSomething(x)的工作。似乎沒有辦法做到這一點。我很欣賞你的建議。 – loop

+1

我意識到這一點,並試圖儘可能接近C++允許的範圍。 'test.x'將在類之外工作,並且'x'可以在類內部工作以用於非變異用法。通過運算符重載,你可以使'x = i;'和'x ++;'也可以工作。但我沒有看到任何方法來避免'changeSomething(x.mutate());' –

相關問題