2016-04-26 132 views
1

最新封裝說我有一類Foo,象這樣一個vector_數據成員:通過返回非const引用成員

class Foo { 
public: 
    const std::vector<int> & vector() const { 
     return vector_; 
    } 
    void vector(const std::vector<int> &vector) { 
     vector_ = vector; 
     // Other operations which need to be done after the 
     // vector_ member has changed 
    } 
private: 
    // Some large vector 
    std::vector<int> vector_; 
}; 

我經常遇到這樣的

void someOperation(std::vector<int> &v) { 
    // Operate on v, but almost always let v's size constant 
} 

int main() { 
    // Create Foo object 
    Foo foo; 
    // Long loop 
    for (auto k = 0; k < 100; k++) { 
     auto v = foo.vector(); 
     someOperation(v); 
     foo.vector(v); 
    } 
} 

的情況下,我可以由於vector訪問成員的方法(const正確)實現,因此不會將foo的(可能很大)vector_成員直接傳遞給someOperation。雖然someOperation幾乎總是讓它的參數大小不變,但我需要首先複製矢量,然後將其傳遞給someOperation,然後傳遞給foo的setter。很顯然,我能避免額外的副本,如果我刪除const -ness的Foo的類的getter和之後的成員已被someOperation改變調用一個方法afterChange - 但是這打破封裝:

class Foo { 
public: 
    std::vector<int> & vector() { // Note we now return by non-const reference 
     return vector_; 
    } 
    void afterChange() { 
     // Other operations which need to be done after the 
     // vector_ member has changed 
    } 
private: 
    std::vector<int> vector_; 
}; 

是否有任何其他的選擇?或者這是破解封裝合法的情況之一?

+3

在我看來,也許'someOperation'應該是對'foo'對象的操作,而不是它應該是'Foo'類中的成員函數。 –

+0

在我看來,如果將此向量傳入和傳出類對象以進行常規處理,則實際上沒有任何封裝可以中斷。 – Galik

+0

@Galik:我不確定我是否明白你的觀點。如果該成員是從類外部修改的(例如,通過返回一個非''contst'引用),我打破封裝(也請注意,setter可能會在成員更改後執行其他操作)。我認爲@RichardHodges提到的替代方案可以更加明確地改變成員,同時提高效率。 – Marcel

回答

3
你的情況

,你可以通過移動向量該集體獲得一些效率並重新:

class Foo { 
public: 
    std::vector<int>&& take_vector() { 
     return std::move(vector_); 
    } 

    void vector(std::vector<int> vector) { 
     vector_ = std::move(vector); 
     // Other operations which need to be done after the 
     // vector_ member has changed 
    } 
private: 
    // Some large vector 
    std::vector<int> vector_; 
}; 

然後...

void someOperation(std::vector<int> &v) { 
    // Operate on v, but almost always let v's size constant 
} 

int main() { 
    // Create Foo object 
    Foo foo; 
    // Long loop 
    for (auto k = 0; k < 100; k++) { 
     // this is a very cheap move 
     auto v = foo.take_vector(); 

     someOperation(v); 

     // so is this 
     foo.vector(std::move(v)); 
    } 
} 

,或者你可以在結構上操作矢量作爲訪問者:

class Foo { 
public: 
    template<class F> 
    void apply_op(F&& op) { 
     op(vector_); 
     // Other operations which need to be done after the 
     // vector_ member has changed 
    } 
private: 
    // Some large vector 
    std::vector<int> vector_; 
}; 

調用像這樣:

void someOperation(std::vector<int> &v) { 
    // Operate on v, but almost always let v's size constant 
} 

int main() { 
    // Create Foo object 
    Foo foo; 
    // Long loop 
    for (auto k = 0; k < 100; k++) 
    { 
     foo.apply_op(&someOperation); 
    } 
} 
0

對於您的情況,您可以將someOperation()更改爲在一定範圍內工作,而不是矢量本身。然後,您的Foo類將需要begin()end()函數,返回適當的迭代器。

相關問題