#c #class-design #encapsulation
Вопрос:
каков наилучший способ поместить класс-контейнер или какой-либо другой класс внутри класса в качестве частного или общедоступного члена?
Требования:
1.Вектор< someclass> внутри моего класса
2.Добавление и подсчет вектора необходим интерфейс
Ответ №1:
Если состояние контейнера является частью инварианта класса, то оно должно, по возможности, быть закрытым.
Например, если контейнер представляет собой трехмерный вектор, то частью инварианта может быть то, что он всегда содержит ровно 3 числа. Предоставление его в качестве общедоступного члена позволит коду, внешнему по отношению к классу, изменять размер контейнеров, что, в свою очередь, может вызвать проблемы для любой процедуры, для которой требуется, чтобы размер контейнера был постоянным. Сохранение контейнера закрытым ограничивает места в вашем программном обеспечении, где размер контейнера может быть изменен в соответствии с функциями-членами класса.
Ответ №2:
Будет ли участник объявлен Частным или Публичным, полностью зависит от вашей заявки. Не могли бы вы рассказать подробнее?
Один важный момент, который следует помнить при объявлении вашего участника, заключается в том, что если вы предоставляете «средство получения» для его извлечения, то вы больше не инкапсулируете этот объект. Вместо этого может быть полезно написать методы-оболочки, раскрывающие только те функции, которые вы хотите раскрыть.
Например, с помощью векторного элемента вы можете написать надстройку и очистить метод, если это все функциональные возможности, которые вы хотите предоставить.
Ответ №3:
Поскольку вы говорите о занятии, я думаю, что оно должно быть частным. Если вы хотите, чтобы он был общедоступным, скорее создайте структуру, чтобы было очевидно, что вы хотите использовать переменные — члены.
Жизнеспособной альтернативой раскрытию vector
участника является создание функции посетителя (или внутреннего итератора). Таким образом, вы лучше подчиняетесь закону Деметры:
class ContWrapper {
std::vector<int> _ints;
public:
class Action {
public:
virtual void accept( int i ) = 0;
};
void each_int( Actionamp; a );
};
Также будьте очень осторожны при экспорте, например std::vector<T>
, из библиотеки: клиентский код может не использовать ту же реализацию STL, что и вы, поэтому расположение этих переменных-членов может отличаться!
Ответ №4:
Сделайте всех участников закрытыми и используйте методы доступа, это позволит вам позже изменить реализацию. Только в очень необычных обстоятельствах я мог бы обнародовать какие-либо данные участника.
Помните, что изменение реализации происходит чаще, чем вы можете себе представить, это не просто случай изменения типа контейнера, но, возможно, вы хотите изменить механизм. Допустим, вы хранили имена в списке, через некоторое время вы можете проиндексировать этот список с помощью хэша и хотели бы, чтобы хэш обновлялся каждый раз, когда вы добавляете новое имя. Если ваша реализация соответствующим образом инкапсулирована, сделать это легко, если вы только что выставили вектор, вам нужно будет внести изменения, которые изменят интерфейс (и поэтому изменения будут заметны).
Если это что-то новое для вас, вы прочитали: http://en.wikipedia.org/wiki/Encapsulation_(классы _ -_компьютеры)
Ответ №5:
Есть и третий способ — иногда лучше наследовать от контейнера и переопределять его методы для достижения вашей цели (например, безопасность потоков). В любом случае, предавать это огласке почти всегда не очень хорошая идея.
Комментарии:
1. Контейнеры STL не имеют виртуальных деструкторов или виртуальных методов, поэтому это может быть опасная территория.
Ответ №6:
Учитывая, что вы хотите инкапсулировать контейнер внутри другого класса, это означает, что он не может быть общедоступным, а также общедоступные методы вашего класса не должны раскрывать ничего специфичного для реализации контейнера. Таким образом, реализация вашего класса (т. е. контейнера) может быть изменена без изменения его интерфейса.