![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Возникла следующая задача, есть сложная структура данных, элементы которой можно читать только последовательно, для этого случая идеально подходит паттерн "итератор". Вопрос в том, где его лучше описывать - внутри класса для доступа к которому он используется, или лучше его описать отдельно. Я понимаю, что оба решения примерно одинаковы, вопрос в том как будет более аккуратно, с учетом возможных последующих изменений.
|
|||
|
||||
| UnrealMan |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Ну, лично мне бы не понравилось видеть определение одного большого класса (где много членов) внутри определения другого большого класса. А вот поместить внутрь определения класса только объявление вложенного класса - это можно. В случае ошибок в диагностическом сообщении компилятора будет хорошо видно, к чему относится вложенный класс.
Это сообщение отредактировал(а) UnrealMan - 17.12.2007, 15:02 |
|||
|
||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Я думал примерно так,
здесь может быть проблема если итератор использует защищенные методы и объявлен другом CBlockPacker-а, если я унаследую от CBlockPacker какой-то класс, то отношение дружбы потеряется, и итератор для производного класса работать перестанет. |
|||
|
||||
| UnrealMan |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Наверное, шаблонными аргументами тут должно быть что-то другое. Некоторые компиляторы в сообщении об ошибке могут сослаться на CBlockIterator<....>, а не CBlockPacker<....>::Iterator. Вот я о чём. Что-то я не понял, где он перестанет работать. Приведи пример. Это сообщение отредактировал(а) UnrealMan - 17.12.2007, 16:06 |
|||
|
||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
описывать снаружи имеет смысл только в случае, если у тебя несколько классов с одинаковым интерфейсом доступа, для которых ты можешь использовать похожую реализацию итераторов.
насчет дружбы идея понятна, понятна и проблема. потому лучше их и не дружить. |
|||
|
||||
| Sartorius |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1568 Регистрация: 18.7.2006 Где: Ivory tower Репутация: 8 Всего: 37 |
ИМХО лучше помещать итератор в класс, с которым он будет работь. К чему плодить шаблоны?
|
|||
|
||||
| UnrealMan |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
А вот мне проблема не понятна. А как тогда обращаться к непубличным членам? Добавлено через 6 минут и 12 секунд У STL разные реализации. Добавлено через 11 минут и 54 секунды Например, в реализации STL от GNU, которая имеется у меня, итератор списка является невложенным классом. |
|||
|
||||
| JackYF |
|
|||
![]() полуавантюрист ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 5814 Регистрация: 28.8.2004 Где: страна тысячи озё р Репутация: 18 Всего: 162 |
Подтверждаю: и у меня тоже. Так что... не факт, не факт. Я бы сказал так: если хватает публичных методов/полей класса для построения итератора - делаем внешний, если не хватает, то тут... не знаю, я склоняюсь ко внешнему, но, имхо, и так, и так сойдёт. |
|||
|
||||
| Lazin |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
вопросов больше нет
это я малость ступил, я подумал что отношение дружбы не наследуется, поэтому тот-же шаблон не будет работать для производного класса(так как другом он объявлен в базовом), но никто не мешает мне объявить итератор другом и в производном. ps есть еще один вариант реализации итератора, это когда ф-ии для перебора элементов коллекции, находятся в классе коллекции. |
||||||
|
|||||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
Не вижу связи. Вложенный класс точно так же не может обращаться к непубличным методам, если он не друг. И с шаблонами все то же, только параметры немного в другом месте описаны. Так что речь только об именах. Вложенный класс - меньше имен. Но. Если в дальнейшем возникнет необходимость в неполных объявлениях, на то вложенный клас без включения хедера не сошлешься, тогда как на внешний - элементарно. Резюме примерно такое: с точки зрения функуциональности - по барабану. Здесь нужно учитывать скорее публичность данного класса. Если это дело нужно сугубо локально, то вложенный класс - хорошее решение. Если речь идет о более широком использовании, лучше внешний клас. А чтобы крепче связать его с целевым контейнером и не громоздить многоэтажные имена, можно все засунуть в пространство имен. Важнее сделать нормальный интерфейс: раз уж называешь iterator, и то вести себя он должен как кошерный STL-итератор. Здесь может помочь boost::iterator_adapter - очень хорошая вешь, три четверти работы за тебя сделает. -------------------- ... |
|||
|
||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
дружба - очень сильная связь. надо иметь достаточно оснований для связи посредством дружбы. именно по этой причине дружба в С++ сделана нетранзитивной. в данном случае дружба дает только доступ к внутреннему устройству класса, что не менее эффективно достигается вложенным классом. а если итератор более общий, то класс, для которого он предназначен, будет иметь некий интерфейс для использования итераторами (или чем-то инициализировать итератор). здесь дружба и не понадобится. а в силу того что дружба не транзитивна, красиво и правильно использовать класс итератора с другими классами не выйдет. |
|||
|
||||
| UnrealMan |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
Earnest уже сказала, что по стандарту вложенный класс, в сравнении со всеми остальными классами, по умолчанию не имеет никаких привилегий касательно доступа к членам содержащего его класса. Хотя многие компиляторы это положение стандарта игнорируют и позволяют свободно обращаться к членам класса из его вложенного класса.
Что ещё за транзитивность дружбы такая? Это сообщение отредактировал(а) UnrealMan - 18.12.2007, 22:41 |
||||
|
|||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
не транзитивность. это означает, что если A дружит с B, а B дружит с C, то это не означает, что А дружит с С |
|||
|
||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 32 Всего: 101 |
Согласен, я был неправ. |
|||
|
||||
| chipset |
|
||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 4071 Регистрация: 11.1.2003 Где: Seattle, US Репутация: 27 Всего: 165 |
ИМХО, тут больше подходит "stack." Что ты будешь делать я вызову *(iter+=2)?
Адназначна --------------------
|
||||||||
|
|||||||||
| Lazin |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
а я не реализую операцию +=
Представь что итератор пользуется несколькими ф-ями из контейнера, для перехода по элементам. Эти ф-ии логично сделать закрытыми, так как клиентам класса не нужно их использовать напрямую, а для этого приходится делать класс другом. Дружба действительно оч. сильная связь, следующая после наследования по силе, но итератор по определению должен быть связан с классом коллекции, так как это всего-лишь вспомогательный класс для доступа к данным коллекции. |
||||
|
|||||
| chipset |
|
||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 4071 Регистрация: 11.1.2003 Где: Seattle, US Репутация: 27 Всего: 165 |
Дружба сильнее наследования поскольку она снимает private а наследование (и то, только public) снимает лишь protected. А вообще чем больше смотрю на твою проблему, тем более она мне напоминает паттерн proxy. А ещё точнее secure proxy. Потому-что все-таки итератор ассоциируется с random access. Если ты запретишь += то я, как юзер, ваще не вникну в чем дело. Да! Мне кажется что основной класс похож на storage и ничего не делает кроме того что хранит данные. ИМХО имеет смысл тупо написать:
А уже потом декорировать как хочешь итераторами и всякой фигней. ЗЫ. Пока модератора нет, вот ещё кусок кода на обозрение публики.
--------------------
|
||||||||
|
|||||||||
| Lazin |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Даже не хранит, а является посредником, но это не важно. Важно то что элементы storage можно получать только строго по порядку, так как туда записываются только изменения(как в cvs репозитории Методы для вычисления очередного элементы содержит класс - storage? так как только он знает формат их хранения, а итератор их вызывает, и хранит промежуточные данные. Так что сдесь скорее такая схема
и использовать можно будет так
жаль в языке нельзя ограничить отношение дружбы несколькими нужными ф-ями |
||||||
|
|||||||
| UnrealMan |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 27 Всего: 32 |
||||
|
||||
| Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 53 Всего: 183 |
Дык выдели этот функционал в отдельный класс и именно с ним дружи, если уж за чистоту борешься... -------------------- ... |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |