2016-04-26 93 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()函数,返回适当的迭代器。

相关问题