0

我想创建一个容器类,它应该允许通过 for each 循环进行迭代,但只能通过 for each 循环。我不想授予对其 .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.
}
4

1 回答 1

0

使用友谊来授予访问权限std::begin并且std::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为该类的一个或多个成员函数。这将仿函数作为参数之一并遍历容器。这使得它通常可供任何想要使用它的人使用,同时仍然对访问数据施加限制。下面的例子提供了一个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);
}

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

于 2013-05-25T22:21:26.703 回答