C++ 我应该在C+中公开迭代器和适配器方法还是整个容器+;?

C++ 我应该在C+中公开迭代器和适配器方法还是整个容器+;?,c++,stl,interface,containers,C++,Stl,Interface,Containers,考虑一下这段代码: class Foo { // ... std::vector<Bar> bars; }; class-Foo { // ... std::矢量条; }; 我应该公开整个容器,还是应该公开typedef'd迭代器类和写适配器方法(begin(),end(),size(),以及我需要的任何方法) 如果答案是“视情况而定”,那么应该如何做出决定?除非绝对需要公开容器,否则只公开迭代器或迭代器范围(以及类型定义的迭代器类型) 这避免了在更改实现细节时破坏其他代

考虑一下这段代码:

class Foo
{ // ...
    std::vector<Bar> bars;
};
class-Foo
{ // ...
std::矢量条;
};
我应该公开整个容器,还是应该公开
typedef
'd迭代器类和写适配器方法(
begin()
end()
size()
,以及我需要的任何方法)


如果答案是“视情况而定”,那么应该如何做出决定?

除非绝对需要公开容器,否则只公开迭代器或迭代器范围(以及类型定义的迭代器类型)

这避免了在更改实现细节时破坏其他代码,并且遵循了信息隐藏/封装的指导原则。

答案是“视情况而定”。)

类的用户需要了解多少关于内部
向量的信息

以标准库中的
堆栈
类为例。它在内部使用标准容器,但它甚至不公开迭代器。它公开了push和pop方法,几乎没有其他内容

该类的用户不需要知道任何其他信息。不应允许类的用户访问堆栈的中间部分。如果这样做,它就不再是一个堆栈

通常,类的用户实际上只需要迭代器。如果您的
Foo
类公开了
begin()
end()
,我还需要什么?我可以随意访问内部数据结构的每个元素。我可以修改它们,或者阅读它们

我是否还需要能够插入/删除元素?也许,如果是的话,我应该直接在向量上这样做,还是通过适配器方法?视情况而定。这个对象代表什么?将对象直接添加到
Foo
拥有的向量中有意义吗?或者将对象添加到
Foo
对象,并让它委托给它喜欢的任何内部实现,这有意义吗?

视情况而定。
如果通过更改容器中pub的状态来更改对象foo的状态,则不应公开容器(因为您可能希望在稍后阶段限制访问,或记录访问)


另一方面,如果foo对象只是一个美化的容器,其中也包含一个向量,那么可能暴露向量是可以的(注意可能)。注意:通过公开向量,您将foo的用户紧密绑定到std::vector,从而在后期将其更改为另一个容器类型可能更难。

如果您只需要读取向量,请公开.begin().end()和迭代器。如果您确实需要添加/删除数据或对其进行更改,请公开整个向量。

不要公开任何内容,请使用瘦包装技术包装调用,并检查一些明显的错误,例如null和索引越界,以及类型和健全性检查


请参阅本网站上的“编写恐怖代码”了解原因,M$的编码者发现他的函数调用作为本周最佳补丁发布在ZD网上。如果您必须编写手动调整的零时间返回并将其公开给其他部分,那么如果您想遵循良好的设计路线,您可能会受到第8部分的影响

您的地图应该是私有的或受保护的,并且它应该看起来像

class Foo
{  
    public:
    typedef std::vector<Bar>::const_iterator FooIterator;
    FooIterator begin()
    {
      return bars.begin();
    }
    FooIterator end()
   {
    return bars.end();
   }
    protected:
    std::vector<Bar> bars;

};

int main()
{
   Foo obj;
   for(obj::FooIterator itr=obj.begin();itr!=obj.end();itr++)
  {
  }
}
class-Foo
{  
公众:
typedef std::vector::const_迭代器FooIterator;
FooIterator begin()
{
返回条。开始();
}
foointerator end()
{
返回杆。结束();
}
受保护的:
std::矢量条;
};
int main()
{
富奥比;
for(obj::FooIterator itr=obj.begin();itr!=obj.end();itr++)
{
}
}

在每一个类中重新实现访问方法的开销可以吗?除了迭代器之外,您还需要什么样的访问方法?没有任何具体情况,一般来说是的。与在容器封装类中更改一些次要的实现细节相比,它比在n个客户机类中潜在地更改代码要好得多。也许以后您不想公开容器的所有内容-然后您只需切换到公开过滤迭代器,客户端代码就不会受到任何影响。@goodrone:begin()
之类的典型访问函数是
内联的,因此没有开销。这是纯粹的语法。