通过自定义容器保护迭代

时间:2013-05-25 22:01:58

标签: c++ oop foreach iterator privacy

我想创建一个容器类,应该允许每个循环可以迭代,但只能通过每个循环。我不想授予其.begin()和.end()方法的访问权限。

这样的事情是否可能,可能是通过重载和std :: begin和std :: end方法的友谊?

我做了一些尝试,其中一个看起来像下面这样。尽管如此,编译器总是抱怨.begin()和.end()的隐私。

namespace std {

    MyIter begin (MySealedContainer&);
    MyIter end (MySealedContainer&);

}

class MyIter {
    // ...
};

class MySealedContainer {
    friend MyIter std::begin (MySealedContainer&);
    friend MyIter std::end (MySealedContainer&);

    private:
        MyIter begin();
        MyIter end();

    // ...
};

// ---

MyIter std::begin (MySealedContainer& c) {
    return c.begin();
}

MyIter std::end (MySealedContainer& c) {
    return c.end();
}

即使使用私人.begin()和.end(),我也可以执行以下操作:

MySealedContainer foo;
// Insert elements...

for (auto& each: foo) {
    // Do something with each.
}

1 个答案:

答案 0 :(得分:0)

使用友情授予对std::beginstd::end的访问权限不会带来任何好处。其他代码可以自由使用它们来访问适配器迭代器,使整个方法无用。 最终它最终会像MySpace一样,没有人想再使用它了。最终你最终会像Facebook一样滥用它并做你不希望他们做的事情。

处理开始/结束的唯一选择是通过友谊授予对各个类和免费功能的访问权限。不幸的是,这会对其使用施加限制,并且每次要授予对其他功能的访问权限时都需要更新。以下示例强调了使用友谊来访问像std::begin

这样的免费函数是徒劳的
class Restricted
{
    int begin() { return 0; }

    friend int std_begin(Restricted&r);
};

int std_begin(Restricted&r)
{
    return r.begin();
}


int main()
{
    Restricted  building;

    // Side step private! might as well just call building.begin()
    int it = std_begin(building);
}

[历史上无足轻重的旧答案]

如果您想限制访问,我建议将for_each实现为该类的一个或多个成员函数。这将functor作为参数之一并遍历容器。这使得它通常可供任何想要使用它的人使用,同时仍然对访问数据施加限制。以下示例提供了for_each函数和要使用的仿函数。

#include <iostream>
#include <vector>

class Adapter
{
public:

    template<typename FuncType>
    void for_each(FuncType &func)
    {
        for(std::vector<int>::iterator it = data_.begin();
            it != data_.end();
            ++it)
        {
            // Pass by value (prevent modification)
            // you can pass the iterator as is if you like!
            func(*it); 
        }
    }
    //private: we leave it public for demo purposes
    std::vector<int>    data_;
};

int main()
{
    Adapter cnt;

    cnt.data_.push_back(1);
    cnt.data_.push_back(2);
    cnt.data_.push_back(3);
    cnt.data_.push_back(4);

    struct {
        void operator()(int value) {
            std::cout << value << std::endl;
        }
    } for_function;

    cnt.for_each(for_function);
}

您需要添加for_each函数的const限定版本,并根据您的要求使用不同数量的参数进行一些重载。使用C ++ 11,您可以选择传递lambda或使用std::function,也可以使用Boost中包含的组件。