STD :: 올바르게 설정하는 방법은 무엇입니까?
-
11-09-2019 - |
문제
멤버로서 std :: set을 가진 입자라는 클래스가 있습니다. 수업은 다음과 같습니다.
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()
기능?
미리 감사드립니다.
편집 : 내가 게시 한 코드는 클래스 구조의 예일뿐입니다. "실제"클래스에는 더 많은 세트 와이 질문에 그다지 중요하지 않은 기타 데이터가 포함되어 있습니다 (나는 가정).
해결책
왜 세트 자체를 노출시키고 싶지 않은지 잘 모르겠지만, 세트의 내용을 외부로 변경할 수 없도록하기 때문입니다. 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
수정). 이것은 혼란을 초래할 수 있습니다.
시도 할 수있는 한 가지는 반복자 (A를 반환하는 몇 가지 멤버 기능을 사용하는 것입니다. begin
그리고 end
, 예를 들어), 클래스 사용자가 반복자를 사용하여 내부 세트에 액세스하고 여전히 세트 구현을 캡슐화 할 수 있도록합니다.
세트의 반복자 유형을 반환 할 수 있거나 더 많은 컨트롤 또는 캡슐화를 원한다면 세트의 반복기를 감싸는 고유 한 반복자 클래스를 구현할 수 있습니다.
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());
}
따라서 내부 반복기를 제거 할 수 있으며 (하나의 반복기 만 갖는 것이 제한적이기 때문에) Particle Iterator의 STL에서 알고리즘을 사용할 수 있습니다.
또한 부스트 :: iterator_facade가 여기에서 유용 할 수 있습니다 ...
문제는 실제로 여기서 달성하려는 것입니다. 지금, 당신의 수업은 (적어도 나에게) 선보다 더 많은 해를 끼치는 것처럼 보입니다. 그것은 세트의 내용을 더 쉽게 어렵게 만듭니다.
나는 입자를보고 그것이 많은 세포를 저장/접근하는 방법을 넘어 의미있는 것을 제공 할 수 있는지 알아냅니다. 실제로 단순한 컨테이너라면, 당신은 같은 것을 훨씬 더 잘할 것입니다. typedef std::set<cell> Particle;
, 따라서 최종 사용자는이 세트에서 다른 세트와 마찬가지로 알고리즘 등을 사용할 수 있습니다. 나는 당신이 의미있는 것을 실제로 캡슐화 할 수 있다면 - 즉 Particle
클래스는 입자에 대한 "지식"을 구현할 수 있으므로 다른 코드는 그 자체로 의미있는 것으로 입자와 함께 작동 할 수 있습니다.
지금, 당신의 Particle
컨테이너 일 뿐이며 특히 좋은 컨테이너처럼 보이지 않습니다. 실제로 무언가를 추가 할 수 없다면 이미있는 것을 사용하는 것이 더 나을 수 있습니다.
당신이 보여주는 것은 세 개의 getters 외에 아무것도하지 않습니다. 이 getters를 입자 클래스의 일부로 사용하는 작업을 수행하여 세트를 캡슐화하면 Getters가 필요하지 않습니다 : Voila, 캡슐화.
이미 보유한 일반 구현을 유지하려면 간단히 제거하십시오. getFirstCell()
, 생성자 내에서 IPC를 초기화 할 수 있습니다. 위에서 언급 한 바와 같이, 신중한 사용 const
접근자와 돌연변이 체 사이의 명확한 차별화는 인터페이스를 명확하게 할 것이다. 또한, 수업에서 반복자를 구현하려면 addcell()
새 셀을 참조하는 반복자를 반환하고 대신 오류가 발생하면 예외를 던집니다.