通过自定义容器的受保护迭代

Protected iteration through custom container

本文关键字:受保护 迭代 自定义      更新时间:2023-10-16

我想创建一个容器类,它应该允许通过for每个循环可迭代,但只能通过for每个循环。我不想授予访问它的。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.
}

使用友谊访问std::beginstd::end不会提供任何好处。其他代码可以自由地使用它们来访问适配器迭代器,这使得整个方法毫无用处。最终它就像MySpace一样,没人想再用它了。最终你会像Facebook一样,每个人都在滥用它,做一些你不希望他们做的事情。

处理begin/end的唯一选择是通过友谊授予对单个类和自由函数的访问权。不幸的是,这将对其使用施加限制,并且每次想要授予对其他函数的访问权限时都需要更新。下面的例子强调了使用友谊来访问像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实现为类的一个或多个成员函数。它接受一个函子作为形参之一,并遍历容器。这使得任何想要使用它的人都可以使用它,同时仍然对访问数据施加限制。下面的示例提供了一个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中包含的组件。