【问题标题】:Protected iteration through custom container通过自定义容器保护迭代
【发布时间】:2013-05-21 04:44:15
【问题描述】:

我想创建一个容器类,它应该允许通过 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.
}

【问题讨论】:

    标签: c++ oop foreach iterator privacy


    【解决方案1】:

    使用友谊授予对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);
    }
    

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

    【讨论】:

    • 我知道这个选项,但我想知道我是否能够使用每个内置的 c++11 遍历我的类,并且仍然可以保护其内容免受个人使用权。我只是发现它比用于 foreaching 的函子或 lambdas 更优雅。
    • 啊。您想将它与 c++11 基于范围的 for 语句一起使用。好吧,那是一家不同的商店。我将更新我的答案以包括解决方案
    • 您应该更新您的问题,以明确您想要基于范围的 for 语句并使用 C++11 对其进行标记。
    • 我已经更新了,不幸的是,与std::begin 和std::end 建立友谊将一无所获。
    • 好吧,我必须克服自己的局限。不过,这不会很难。非常感谢。 (y)
    猜你喜欢
    • 2013-02-17
    • 2021-09-15
    • 1970-01-01
    • 2020-12-08
    • 2015-02-04
    • 2015-09-06
    • 1970-01-01
    • 2012-11-18
    相关资源
    最近更新 更多