通过向成员返回非const引用来打破封装

时间:2016-04-26 04:43:40

标签: c++ c++11

假设我有一个Foo课程,其vector_数据成员如此:

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);
    }
}

由于(foo - 正确)vector_的实现,我无法将someOperation的(可能很大的)const成员直接传递给vector 1}}访问成员的方法。虽然someOperation几乎总是让其参数的大小保持不变,但我需要先复制向量,然后将其传递给someOperation,然后传递给foo的setter。显然,如果删除const类getter的Foo - 并在成员被{{1}更改后调用afterChange方法,我可以避免使用此额外副本} - 但这打破了封装:

someOperation

还有其他选择吗?或者这是打破封装合法的情况之一?

2 个答案:

答案 0 :(得分: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);
    }
}

答案 1 :(得分:0)

在您的情况下,您只需更改someOperation()即可在范围内工作,而不是向量本身。然后,您的Foo类需要begin()end()函数,并返回适当的迭代器。