Pergunta

Eu tenho uma classe chamada de partículas que tem um std :: set como um membro. Os olhares de classe como este:

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

Estou muito descontente com o getFirstCell(), getNextCell() e, especialmente, hasNextCell(), eles existem, porque eu não quero expor o conjunto em si. Eu tive que usar o caminho através ++ipc e --ipc porque if((ipc+1) == this->cells.end()) dá um erro do compilador, ipc + 1 parece ser o problema.

O que seria uma boa maneira de encapsular um conjunto e acessá-lo? Além disso, existe uma boa maneira de se livrar da função getFirstCell()?

Agradecemos antecipadamente.

Edit: O código eu postei é apenas um exemplo da estrutura de classes. A classe "real" contém mais conjuntos e outros dados que não é tão importante para esta pergunta (eu assumi).

Foi útil?

Solução

Eu não sei por que você não deseja expor o conjunto em si, mas se é porque você quer garantir que o conteúdo do conjunto não pode ser alterada class Particle fora apenas retornar iterators const que torna o conjunto de "leitura apenas", por exemplo

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

Outras dicas

A razão que ipc+1 não trabalho é só isso std::set suporta iteradores bidirecionais, que operator++ apoio e operator--; Para utilizar operator+, você precisa usar iteradores de acesso aleatório.

Uma preocupação que vejo com seu projeto é que suas funções são nomeadas como assessores (getSuchAndSuch), mas eles também modificar o estado interno do objeto (ipc é modificado). Isso pode levar a confusão.

Uma coisa que você poderia tentar seria a utilização de algumas funções de membro que iterators retorno (um begin e end, por exemplo), e permitem que os usuários de sua classe para iterators usar para acessar o conjunto interno, enquanto ainda encapsular o conjunto implementação.

Você poderia retornar do set tipo iterator ou se você quiser mais controle ou encapsulamento, você poderia implementar sua própria classe iterator que envolve iteração do conjunto.

Para evitar set expondo :: iterator (para não prometem aos usuários mais do que o necessário), você pode criar um 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());
}

Assim, você vai se livrar de iterador interno (porque é bastante restritiva para ser capaz de ter apenas um iterator) e terá capacidade de usar algoritmos de STL em iterators partícula.

Além disso boost :: iterator_facade pode ser útil aqui ...

A questão é realmente o que você está tentando realizar aqui. Agora, sua classe parece (pelo menos para mim) para fazer mais mal do que bem -. Que torna o trabalho com o conteúdo do conjunto mais difícil, em vez de mais fácil

Eu olhava para partículas, e descobrir se ele pode fornecer algo significativo para além de alguma forma de armazenar / acesso a um grupo de células. Se ele realmente é apenas um recipiente simples, então você estaria muito melhor com algo como typedef std::set<cell> Particle;, de modo que o usuário final pode usar algoritmos e tal sobre este conjunto apenas como eles podem de qualquer outro. Eu só escrever uma classe para encapsular que se você pode realmente encapsular algo significativo -. Ou seja, se sua classe Particle pode encarnar algum "conhecimento" sobre partículas tão outro código pode trabalhar com uma partícula como uma coisa que é significativo em si

Agora, o seu Particle nada mais é que um recipiente - e não se parece com um particularmente bom recipiente quer. A menos que você pode realmente adicionar algo, você pode ser melhor fora apenas usando o que já está lá.

o que você mostra não faz nada além dos três getters. encapsular o conjunto, tornando as operações que usam estes getters parte da classe de partículas, então você não vai precisar dos getters em tudo:. voila, encapsulado

Se você gostaria de manter a aplicação geral que você já tem, mas simplesmente eliminar getFirstCell(), você pode inicializar ipc dentro do construtor. Como indicado acima, o uso criterioso de const e clara diferenciação entre assessores e modificadores clarificará a interface. Além disso, se você fosse para implementar iteradores em sua classe, então eu recomendaria que addcell() retornar um iterador referenciando a nova célula e, em vez lançar uma exceção ao encontrar um erro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top