0

メンバとして std::set を持つ Particle という名前のクラスがあります。クラスは次のようになります。

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()また、関数を取り除く良い方法はありますか?

前もって感謝します。

編集:私が投稿したコードは、クラス構造の単なる例です。「実際の」クラスには、この質問にとってそれほど重要ではないより多くのセットとその他のデータが含まれています (私は想定しています)。

4

6 に答える 6

4

ipc+1が機能しない理由は、とstd::setをサポートする双方向イテレータのみをサポートするためです。を使用するには、ランダム アクセス イテレータを使用する必要があります。operator++operator--operator+

私があなたの設計で見た懸念の 1 つは、関数がアクセサー (getSuchAndSuch) のように名前が付けられていることですが、オブジェクトの内部状態も変更します (ipc変更されます)。これは混乱を招く可能性があります。

試してみることができることの 1 つは、イテレータを返すいくつかのメンバー関数 (a beginおよびendなど) を使用し、クラスのユーザーがイテレータを使用して内部セットにアクセスできるようにする一方で、セットの実装をカプセル化することです。

セットの反復子の型を返すか、さらに制御またはカプセル化が必要な場合は、セットの反復子をラップする独自の反復子クラスを実装できます。

于 2009-12-02T16:56:11.193 に答える
4

セット自体を公開したくない理由はわかりませんが、セットの内容を外部で変更できないようにしたい場合は、セットを「読み取り専用」にする反復子をclass Particle返すだけです。const

typedef std::set<vtkIdType>::const_iterator CellIterator;
CellIterator beginCell() const { return this->cells.begin(); }
CellIterator endCell() const { return this->cells.end(); }
于 2009-12-02T17:02:18.887 に答える
2

set :: iteratorの公開を防ぐために(必要以上にユーザーに約束しないために)、ラッパーを作成できます。

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());
}

したがって、内部イテレータを取り除き(1つのイテレータしか持てないことが非常に制限されているため)、ParticleのイテレータでSTLのアルゴリズムを使用できるようになります。

また、boost::iterator_facadeはここで役立つかもしれません...

于 2009-12-02T17:12:41.673 に答える
1

問題は、ここで何を達成しようとしているのかです。現時点では、あなたのクラスは (少なくとも私には) 良いことよりも悪いことをしているように見えます。セットの内容を操作するのが簡単ではなく、難しくなっています。

私は Particle を見て、多数のセルを保存/アクセスする方法を超えて意味のあるものを提供できるかどうかを判断します。それが本当に単純なコンテナーである場合は、 のようなものを使用する方がはるかに優れてtypedef std::set<cell> Particle;いるため、エンドユーザーはこのセットで他のものと同じようにアルゴリズムなどを使用できます。意味のあるものを本当にカプセル化できる場合、つまり、Particleクラスが粒子に関する「知識」を具現化できる場合にのみ、それをカプセル化するクラスを作成し、他のコードが粒子をそれ自体が意味のあるものとして機能できるようにします。

現時点では、あなたParticleのコンテナはコンテナにすぎません。また、特に優れたコンテナのようにも見えません。本当に何かを追加できる場合を除き、既にあるものをそのまま使用する方がよい場合があります。

于 2009-12-02T17:23:39.780 に答える
0

あなたが示すものは、3つのゲッター以外には何もしません。これらのゲッターを使用する操作を Particle クラスの一部にすることでセットをカプセル化すると、ゲッターはまったく必要なくなります。ほら、カプセル化されます。

于 2009-12-02T16:54:48.650 に答える
0

すでに持っている一般的な実装を保持したいが、単純に を削除getFirstCell()したい場合は、コンストラクター内で ipc を初期化できます。前述のように、constアクセサーとミューテーターを適切に使用し、明確に区別することで、インターフェイスが明確になります。さらに、クラスに反復子を実装する場合はaddcell()、新しいセルを参照する反復子を返し、代わりにエラーが発生したときに例外をスローすることをお勧めします。

于 2009-12-02T17:08:43.307 に答える