Закон Деметры или вернуть весь вектор - PullRequest
4 голосов
/ 25 марта 2009

Какой из них лучше:

public:
  const vector<int> & GetPointsVector();
private:
  vector<int> PointsVector;

Или:

public:
  int GetCurrentPoint();
  void MoveToFirstPoint();
  void MoveToNextPoint();
  bool IsAtLastPoint();
  size_t GetNumberOfPoints();
private:
  vector<int> PointsVector;

Ответы [ 5 ]

13 голосов
/ 25 марта 2009

Оба нет. Лучше вернуть итераторы begin () и end () или еще лучше boost :: range для итератора.

private:
        typedef std::vector<int>            PointsContainer;
public: 
        typedef boost::iterator_range<PointsContainer::const_iterator> PointsRange;
        PointsRange getPointsRange() const {
            return boost::make_iterator_range(pointsContainer_.begin(), pointsContainer_.end()); 
        }

Преимущество заключается в том, что логика обхода скрыта внутри диапазона / итератора

При использовании одной альтернативой является:

int p;
foreach(p, obj.getPointsRange()) {
   //...
}

в противном случае

C::PointsRange r = obj.getPointsRange();
for(C::PointsRange::iterator i = r.begin(); i != r.end(); ++i) {
      int p = *i;
      //...
}
2 голосов
/ 25 марта 2009

Нет правильного ответа. Ответ будет зависеть от контекста, которого у нас в настоящее время очень мало.

Это зависит от клиентов вашего класса. В большинстве ситуаций вы не хотели бы, чтобы случайный инспектор изменял состояние объекта, поэтому в определенной степени лучше возвращать ссылку на const объект. Однако в таком случае я бы также сделал функцию const, т.е.

 /* a design const - this accessor does not change the state */
 const vector<int> & GetPointsVector() const;

Это также эффективно, поскольку вы не передаете тяжелые объекты в качестве возвращаемых значений (это другой вопрос, что большинство компиляторов делают RVO в наши дни).

Если ваш клиент должен использовать вектор в алгоритмах, да, вам лучше предоставить итераторы. Но две пары, т.е.

typedef vector<int>::iterator _MyItr;
_MyItr begin() const;
_MyItr begin();

_MyItr end() const;
_MyItr end();

Это соответствует способу разработки STL. Но будьте осторожны при указании того, какого рода итератор может ожидать клиент (например: если спецификация класса говорит, что возвращаемые итераторы RandomIterators, это устанавливает определенное ожидание для вашей реализации).

2 голосов
/ 25 марта 2009

По моему мнению, первая альтернатива (строго с ключевым словом const) лучше, так как тогда вы можете использовать стандартные интерфейсы для доступа к элементам вектора (таким как итераторы и т. Д.). Второй вариант (т. Е. Специальные методы доступа) требуется только в том случае, если у вас нет другого варианта защиты данных от случайных изменений.

2 голосов
/ 25 марта 2009

Ни. Превратите функцию, которая нуждается в таком глубоком знании внутренних элементов класса, в функцию-член.

0 голосов
/ 25 марта 2009

Я предпочитаю инкапсулировать внутреннее представление данных и использовать публичную функцию шаблона forEachSomething. Или, если у вас есть повышение, вы можете избежать шаблонного forEachSomething и поместить реализацию в файл .cpp.

class Class
{
public:
    Class()
    {
        points_.push_back( 1 );
        points_.push_back( 5 );
        points_.push_back( 7 );
    }

    template <typename TFunction>
    void forEachPoint( TFunction function )
    {
        std::for_each( points_.begin(), points_.end(),
                       function );
    }

    void forEachPoint2( boost::function< void (int ) > function )
    {
        std::for_each( points_.begin(), points_.end(),
                       function );
    }
private:
    std::vector<int> points_;
};

void print( int a )
{
    std::cout << a << std::endl;
}

int main()
{
    Class object;
    object.forEachPoint( print );
}
...