2010-06-01 53 views
6

我正在將一個結構轉換爲一個類,所以我可以爲我的變量強制執行一個setter接口。
雖然我不想更改變量被讀取的所有實例。 所以我將這筆:此C++ const引用訪問器接口習慣用法的任何問題?

struct foo_t { 
    int x; 
    float y; 
}; 

這樣:

class foo_t { 
    int _x; 
    float _y; 
public: 
    foot_t() : x(_x), y(_y) { set(0, 0.0); } 

    const int &x; 
    const float &y; 

    set(int x, float y) { _x = x; _y = y; } 
}; 

我很感興趣,這是因爲它似乎建模C#的公共只讀屬性的想法。
編譯好,我還沒有看到任何問題。

除了常量引用在構造函數關聯的樣板,有什麼缺點,以這種方法嗎?
任何奇怪的別名問題?
爲什麼我之前沒看過這個成語?

+0

爲什麼是const int的&X; const float&y;需要? – Arun 2010-06-01 19:47:06

+0

@阿爾莎莎他在他的問題中解釋說。目的是爲'x'和'y'提供一個「訪問器」,它保持與訪問結構中的變量相同的語法。 – 2010-06-01 19:49:36

+1

C#和C++是完全不同的語言,有自己的風格和用法。複製在另一個語言會導致很多麻煩的風格是簡單了很多學習的最佳技術,新語言無法複製的風格可能不兼容(如geter/seter的可怕的概念) – 2010-06-01 19:52:51

回答

5

由於您公開了對foo_t的內部數據的引用,因此foo_t對象外部的代碼可能會在對象的生命週期內持續引用其數據。試想一下:

foo_t* f = new foo_t(); 
const int& x2 = f->x; 
delete f; 
std::cout << x2; // Undefined behavior; x2 refers into a foo_t object that was deleted 

甚至更​​簡單:

const int& x2 = foo_t().x; 
std::cout << x2; // Undefined behvior; x2 refers into a foo_t object that no longer exists 

這些都不是特別現實的例子,但是這是一個潛在的問題,每當一個對象公開或返回到它的數據的引用(公共或私人)。當然,儘可能在一生中堅持提及foo_t對象本身,但這可能更難以錯過或偶然發生。

不,這是對你在做什麼的爭論。事實上,我之前使用過這種模式(出於不同的原因),除了缺少封裝外,我認爲它沒有任何內在的錯誤,您似乎認識到了這一點。上述問題只是需要注意的一點。

+0

我懷疑這樣的事 - 謝謝。 – mskfisher 2010-06-01 20:04:03

0

你的做法是不靈活。如果每個變量都有getter/setter,則表示如果向班級添加內容,則不必重寫set方法。

這是不好的,因爲你不能有constnon-const獲得者(它很少使用,但有時可能會有用)。

您不能複製引用,因此,您的類成爲不可複製的。

另外,在你的類中初始化引用意味着額外的內存,如果我們正在談論,例如頂點類(儘管我認爲它實際上不應該是一個類),這可能會變成一場災難。


[遵循一切完全是主觀] getter和setter

目的,在我看來,是不是簡單的修改,而是關於封裝的一系列動作導致的值修改或返回值(我們將其視爲可見結果)。

在你的例子的情況下,個人結構會更有效,因爲它包裝POD數據和邏輯「structurizes」吧。

11

的一個問題是,你的類不再可複製或分配的,因此不能存儲在像載體C++的容器。另一個是維護你的代碼的經驗豐富的C++程序員會看着它並驚歎「WTF !!」非常大聲,這從來都不是好事。

+1

Touche。但我可以通過定義它們來解決這個問題(爲了簡潔起見我省略了這些)。 – mskfisher 2010-06-01 19:47:46

+0

(我喜歡你的編輯如何使我的評論模棱兩可 - 我現在可以既可以指「定義拷貝構造函數」或「定義有經驗的C++程序員」) – mskfisher 2010-06-01 20:06:44

+0

@mskfisher就是這樣的SO奇蹟 - 事實是,你的評論不應該阻止我改進答案。任何感到困惑的人都可以看看編輯歷史。我必須說我發現你的評論含糊不清 - 在我最初的回答中,「他們」是什麼? – 2010-06-01 20:11:34

2

你也可以做這樣的事情,它適用於內建類型: (很抱歉,如果這一代碼段包含錯誤,但你的想法)

template <typename T, typename F> 
class read_only{ 
    typedef read_only<T, F> my_type; 
    friend F; 

public: 
    operator T() const {return mVal;} 

private: 
    my_type operator=(const T& val) {mVal = val; return *this;} 
    T mVal; 
}; 


class MyClass { 
public: 
    read_only <int, MyClass> mInt; 
    void MyFunc() { 
     mInt = 7; //Works 
    } 
}; 

AnyFunction(){ 
    MyClass myClass; 
    int x = myClass.mVal; // Works (okay it hasnt been initalized yet so you might get a warning =) 
    myClass.mVal = 7; // Error 
} 
+0

我不得不說這很聰明。 – 2010-06-01 20:05:37

+0

我也喜歡你已經避開了常量引用的價值回報,這消除了泰勒對我的方法的抱怨。 – mskfisher 2010-06-01 20:10:23

+1

AFAIR模板參數不能成爲朋友,所以它不起作用,即使它起作用,它也應該是「朋友類F」。有一些技巧可以解決這個問題,因爲它們很討厭,並且無處不在。 – Tomek 2010-06-01 20:35:45