Domanda

Ho una classe denominata particella che ha uno std :: set come membro. La classe si presenta così:

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

Sono molto soddisfatto della getFirstCell(), getNextCell() e soprattutto hasNextCell(), esistono perché io non voglio esporre l'apparecchio stesso. Ho dovuto usare il percorso attraverso ++ipc e --ipc perché if((ipc+1) == this->cells.end()) dà un errore di compilazione, IPC + 1 sembra essere il problema.

Quale sarebbe un buon modo per incapsulare un set e accedervi? Inoltre, c'è un bel modo per sbarazzarsi della funzione getFirstCell()?

Grazie in anticipo.

Modifica: Il codice che ho postato è solo un esempio della struttura classi. La classe "reale" contiene più insiemi e altri dati che non è così importante per questa domanda (ho assunto).

È stato utile?

Soluzione

Non sono sicuro che il motivo per cui non si vuole esporre l'apparecchio in sé, ma se è perché si vuole garantire che il contenuto del set non può essere modificato al di fuori class Particle solo tornare iteratori const che rende il set "di sola lettura solo", ad esempio

typedef std::set<vtkIdType>::const_iterator CellIterator;
CellIterator beginCell() const { return this->cells.begin(); }
CellIterator endCell() const { return this->cells.end(); }

Altri suggerimenti

La ragione per cui ipc+1 non funziona è che std::set supporta solo iteratori bidirezionali, che sostengono operator++ e operator--; al fine di utilizzare operator+, è necessario utilizzare gli iteratori ad accesso casuale.

Una preoccupazione che vedo con il vostro disegno è che le funzioni sono chiamati come funzioni di accesso (getSuchAndSuch) ma anche modificare lo stato interno dell'oggetto (ipc viene modificato). Questo potrebbe portare a confusione.

Una cosa che si potrebbe provare sarebbe quella di utilizzare alcune funzioni membro che restituiscono iteratori (un begin e end, per esempio), e consentire agli utenti della vostra classe di usare iteratori per accedere al set interno, mentre ancora incapsulando il set implementazione.

Si potrebbe restituire il set del tipo iteratore o se si desidera un maggiore controllo o incapsulamento, è possibile implementare la propria classe iteratore che avvolge iteratore del set.

Per evitare di esporre set :: iterator (di non promettete di utenti più del necessario) è possibile creare un wrapper:

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

In questo modo si sbarazzarsi di iteratore interno (perché è abbastanza restrittivo per essere in grado di avere un solo iteratore) e avranno la capacità di utilizzare gli algoritmi da STL su iteratori di particelle.

Anche dare impulso :: iterator_facade può essere utile qui ...

La domanda è davvero quello che si sta cercando di realizzare qui. In questo momento, la classe sembra (almeno a me) per fare più male che bene -. Lo rende il lavoro con i contenuti del set più difficile anziché più facile

mi aspetto a particelle, e capire se può fornire qualcosa di significativo al di là di un certo modo di immagazzinare / accesso a un gruppo di cellule. Se è davvero solo un semplice contenitore, allora si sarebbe molto meglio di con qualcosa di simile typedef std::set<cell> Particle;, in modo che l'utente finale può utilizzare algoritmi e come su questo set, proprio come il possibile qualsiasi altro. Mi piacerebbe scrivere solo una classe per incapsulare che se si può veramente incapsulare qualcosa di significativo -. Vale a dire se la classe Particle può incarnare qualche "conoscenza" sulle particelle in modo da altro codice può lavorare con una particella come una cosa che è significativo in sé

In questo momento, la tua Particle non è altro che un contenitore - e non sembra particolarmente buon contenitore sia. A meno che non si può davvero aggiungere qualcosa, si potrebbe essere meglio solo utilizzando ciò che c'è già.

ciò che si mostra non fa nulla oltre alle tre getter. incapsulare il set, rendendo le operazioni che userebbero questi getter parte della classe delle particelle, quindi non sarà necessario i getter a tutti:. voilà, incapsulato

Se vuoi mantenere l'attuazione generale avete già, ma semplicemente eliminare getFirstCell(), si potrebbe inizializzare IPC all'interno del costruttore. Come indicato in precedenza, l'uso giudizioso di const e differenziazione chiara tra accessori ed i mutatori potrebbe chiarire l'interfaccia. Inoltre, se si dovesse implementare iteratori sulla tua classe, allora vi consiglio che addcell() restituire un iteratore riferimento alla nuova cella, e invece un'eccezione su di un errore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top