Инкапсуляция вектора - PullRequest
1 голос
/ 29 ноября 2011

Вот небольшой образец моего класса:

#include <string>
#include <vector>

using std::string;
using std::vector;

struct Book {
  string m_author;
  string m_title;
};

class BookList
{
public:
  BookList();
  ~BookList();

private:
  vector<Book*> m_books;
}

Как видите, данные для BookList хранятся в виде vector из Book с. Как лучше написать аксессор? Должен ли я позволить пользователю получать их один за другим с помощью методов HasMore() & GetNextBook(), или было бы лучше просто вернуть весь вектор? Или, может быть, итератор?

Заранее спасибо.

Ответы [ 5 ]

1 голос
/ 29 ноября 2011

Прежде всего, вам, вероятно, не нужно хранить указатель. Вместо этого используйте значение. И здесь у вас есть один из трех вариантов:

  1. Вернуть вектор по значению или по ссылке.
  2. Предоставить начало / конец итераторов.
  3. Просто сделайте вектор открытым или вообще избавьтесь от BookList и просто используйте std::vector<Book> напрямую.

GetNextBook подход плохой, потому что он делает ваше состояние итерации хранилища списков без веской причины. А также делает вас единственным человеком, который делает это.

1 голос
/ 29 ноября 2011

Если вы не добавляете какие-либо дополнительные функции в класс, вы можете вместо этого использовать typedef:

typedef vector<Book*> BookList;

Если вы добавляете дополнительные функции, предоставьте итераторы begin() и end(), аналогичные контейнерам STL, плюс методы модификации.

0 голосов
/ 30 ноября 2011

Как уже упоминалось, удаление класса BookList и его замена на соответствующий typedef, вероятно, является наилучшим вариантом, если у BookList нет других обязанностей.Однако, если требуется BookList, то некоторые опции для предоставления доступа к m_books будут следующими:

  • метод, который возвращает vector< Book* > const &
  • пару begin/ end методы, которые возвращают полиморфные обертки итератора, такие как this или this

Первый вариант является самым простым, но предоставляет внутреннее расположение данных клиентам,Второй вариант позволит вам заменить базовый контейнер, не требуя каких-либо изменений для клиентов.Вам решать, какой из них наиболее подходит для вашего дизайна.

Кроме того, вы можете рассмотреть возможность замены vector< Book* > на vector< Book >, если Book не будет полиморфным базовым классом.Если это так, то, вероятно, лучшим вариантом будет контейнер умных указателей.

0 голосов
/ 29 ноября 2011

В конечном счете, вы хотите сделать это как можно более абстрактным, по крайней мере, для всего публичного.Есть несколько вещей, о которых стоит подумать:

  • Если вы вернете все это, вы рискуете, что публика сможет изменить вектор.Вы действительно хотите, чтобы они могли это сделать?
  • Что если вам нужно изменить макет класса в какой-то момент?Если вы напишите свои собственные методы для возврата требуемых данных, это позволит вам заменить vector в какой-то момент в будущем, не нарушая совместимость со всем остальным.
  • Возвращение всего вектора даст массивный кадр стека.В идеале вам нужно будет передать указатель.

Если вам, вероятно, не понадобится менять реализацию, возврат итератора может сработать.

0 голосов
/ 29 ноября 2011

Возвращаем ссылку на вектор или пару итераторов. Написание аксессоров / переопределение интерфейса итераторов нестандартным способом бессмысленно. Другой вариант, иногда полезный, состоит в извлечении вашего класса из контейнера STL.

...