如何封装一个std ::设置正确吗?
-
11-09-2019 - |
题
我有一个类名为粒子,其具有一个std ::设置为成员。类看起来像这样:
class Particle {
private:
std::set<vtkIdType> cells;
std::set<vtkIdType>::iterator ipc;
public:
Particle() {};
enum state {EXISTS = -1, SUCCESS = 0, ERROR = 1};
state addCell(const vtkIdType cell);
int numCells() { return static_cast<int>(cells.size()); }
vtkIdType getFirstCell() { return (*(ipc = this->cells.begin()));}
vtkIdType getNextCell() { return *(++ipc); }
vtkIdType hasNextCell() { ++ipc; if (ipc == this->cells.end()) return false; --ipc; return true; }
std::string getOutput();
};
我很不满getFirstCell()
,getNextCell()
尤其是hasNextCell()
,他们的存在是因为我不想暴露自己设定。我不得不通过++ipc
和--ipc
使用方式,因为if((ipc+1) == this->cells.end())
给出了一个编译器错误,IPC + 1似乎是问题。
什么是封装了一组和访问它的好办法?此外,有没有摆脱getFirstCell()
功能的一个很好的方式?
预先感谢。
编辑:我发布的代码只是类结构的一个例子。 “真正的”类包含更多组和其它数据是不为这个问题(I假定)。
这重要解决方案
我不知道为什么你不想暴露组本身,但如果是因为要确保集的内容不能外class Particle
改变只是返回const
迭代这使得集“读 - 只有”,例如
typedef std::set<vtkIdType>::const_iterator CellIterator;
CellIterator beginCell() const { return this->cells.begin(); }
CellIterator endCell() const { return this->cells.end(); }
其他提示
这ipc+1
不起作用的原因是,仅std::set
支持双向迭代器,这支持operator++
和operator--
;为了使用operator+
,您需要使用随机访问迭代器。
一个问题我与您的设计看到的是,你的功能被命名为喜欢存取(getSuchAndSuch),但他们也修改对象的内部状态(ipc
被修改)。这可能导致混淆。
一件事,你可以尝试将使用返回迭代器(一个begin
和end
,例如)一些成员函数,并允许类的用户使用迭代器来访问内部设定,同时还封装集实施
您可以返回集合的迭代器类型,或者如果你想要更多的控制或封装,你可以实现一个包装集合的迭代器自己的迭代器类。
要防止暴露组:迭代(到不承诺用户超过需要的话)可以创建一个包装:
class Particle::iterator
{
public:
iterator()
{}
iterator &operator++()
{
++InternalIterator;
return *this;
}
vtkIdType &operator*() const
{
return *InternalIterator;
}
...//other functionality required by your iterator's contract in the same way
private:
iterator(const std::set<vtkIdType> &internalIterator)
:InternalIterator(internalIterator)
{}
std::set<vtkIdType>::iterator InternalIterator;
};
Particle::iterator Particle::GetBeginCell()
{
return iterator(cells.begin());
}
Particle::iterator Particle::GetEndCell()
{
return iterator(cells.end());
}
因此,你将摆脱内部迭代器(因为它是相当严格的,以便能够只有一个迭代器),并会得到使用来自STL算法对粒子的迭代器的能力。
也助推:: iterator_facade可能是有用的在这里...
真正的问题是你要在这里完成的。现在,你好像类(至少对我来说)做弊大于利 - 它与集更加困难,而不是容易的工作内容
我想看看粒子,并弄清楚它是否能提供一些有意义的事情超出了存储/访问一堆细胞的某种方式。如果真的只是一个简单的容器,那么你最好是用类似typedef std::set<cell> Particle;
好了很多,所以最终用户可以使用算法和这种这套就像他们可以在任何其他。我只写一个类来封装,如果你真的可以封装有意义的事 - 即,如果你Particle
类可以体现一些“知识”关于颗粒,这样其他的代码可以用粒子为这本身就是有意义的事情努力
现在,你Particle
不过是一个容器 - 它看起来并不像一个特别好的容器,无论是。除非你真的可以添加一些东西,你可能会更好只使用什么是已经存在。
告诉你不这样做,除了三大干将的任何事情。通过使将使用粒子类的这些干将一部分,那么你就不需要在干将所有操作封装集:瞧,封装
如果你想留住你已经拥有了一般执行,而只是消除getFirstCell()
,你可以在构造函数中初始化IPC。如上所述,明智地使用accessor和mutator之间const
和明确的分化将澄清的接口。此外,如果你要实现你的类迭代器,那么我会建议addcell()
返回一个迭代引用新的细胞,而是发生错误时抛出异常。