1. сейчас Вам объяснят что не для каждого, а только там где нужно, и здесь я, в принципе, соглашусь
2. есть всевозможне property, но в builder свои, в visual studio свои, etc. короче непереносимо и коряво
3. можно реализовать черезкостыльное решение на стандартном C++, если интересно можно развить;
4. можно используя C++0x через variadic templates (где доступно) и функторы
статью не читал, но уверен что публичные атрибуты лучше делать через геттер/сеттер. по той причине что внутри класса пляски вокруг атрибута могут стать нетривиальными - поэтому лучше сразу обернуть это в методы дабы не ломать интерфейс класса и блюсти инкапсуляцию.
Сейчас в вашем распоряжении имеются гигантские тома, посвященные паттернам проектирования, и каждые несколько месяцев кто-нибудь новый предлагает очередную методологию разработки, клянясь при этом, что ее использование превратит вас в Бога среди программистов.
Но то, что хорошо выглядит на бумаге, не всегда работает на практике. И то, что вы можете что-то делать, вовсе не означает, что вы обязаны это делать. Программисты, которые занимаются фетишизмом своих инструментов разработки, неминуемо упускают из виду этот момент, и даже простейший из проектов может погрязнуть в аду разработки. Сопротивляйтесь этим низменным импульсам и придерживайтесь тех решений, которые действительно работают.
вся идея ООП состояла в мышлении от интерфейсов, позволяющему более или менее свободно варьировать реализацию; мышление от реализации (есть поле - надо сделать к нему геттер/сеттер) означает отказ от этой идеи и возвращение к переносимому ассемблеру. в разработке любого крупного проекта в любом случае придётся идти на ряд компромиссов, так зачем сознательно ещё усложнять себе жизнь, отказываясь от естественных плюсов выбранного подхода?
геттеры/сеттеры, кстати, хорошо работают именно на бумаге - бумаге тысяч популярных книжонок, утверждающих повышение инкапсуляции при их использовании. плохо они начинают работать уже потом, в реальной жизни
>статью не читал, но уверен что публичные атрибуты лучше делать через геттер/сеттер. по той причине что внутри класса пляски вокруг атрибута могут стать нетривиальными - поэтому лучше сразу обернуть это в методы
Вот прочитаешь статью по ссылке и поймёшь, что оба варианта одинаково хреновы
>в приведённом случае вместо класса идеально подойдёт структура
А если я захочу две координаты сразу изменить? p.x=, p.y=? А если мне надо, чтобы по умолчанию объект инициализирован был? memset? А если захочу контроллировать координаты, например, мои точки могут жить только в первом квадранте. По коду искать все присваивания и размазывать if( p.x < 0 ) ...?
Список можно до бесконечности продолжить.
>в приведённом случае вместо класса идеально подойдёт структура
А если я захочу две координаты сразу изменить? p.x=, p.y=? А если мне надо, чтобы по умолчанию объект инициализирован был? memset? А если захочу контроллировать координаты, например, мои точки могут жить только в первом квадранте. По коду искать все присваивания и размазывать if( p.x < 0 ) ...? Список можно до бесконечности продолжить.
а если произойдёт землетрясение? да покласть тебе будет на реализацию этой точки - нет универсального решения на все случаи жизни
>а если произойдёт землетрясение? да покласть тебе будет на реализацию этой точки - нет универсального решения на все случаи жизни
На все случаи жизни - нет. Но есть на 80% не форсмажоров. Если оставить эту структуру в виде POD-типа - со временем будет макаронный код. Если оформить в виде класса даже с простейшими геттерами/сеттерами - можно избежать множества проблем в будущем.
Если оставить эту структуру в виде POD-типа - со временем будет макаронный код. Если оформить в виде класса даже с простейшими геттерами/сеттерами - можно избежать множества проблем в будущем.
термин «spaghetti code» относится к наличию многочисленных ветвлений и переходов, затрудняющих чтение и понимание кода, не понимаю откуда они возьмутся в рассматриваемом примере и как использование аксессоров может предотвратить это
>термин «spaghetti code» относится к наличию многочисленных ветвлений и переходов, затрудняющих чтение и понимание кода, не понимаю откуда они возьмутся в рассматриваемом примере и как использование аксессоров может предотвратить это
Привел же пример. Пусть надо добавить контроль корректности данных, которые в точку кладутся. В случае, если доступ идет через сеттер, ветвление надо будет поставить в одном месте, если напрямую к полям - найти в коде все присваивания и размазать if'ы по всему коду.
>А зачем твоей программе по всему коду пытаться класть в точку некорректные данные?
Для людей, которые ошибок никогда не делали, не знают, что такое отладка, не переделывали имеющийся проект под новые требования, не работали со сторонними библиотеками и в команде - для них мой пост малоинформативен и непонятен, да. Зачем это еще морочиться с инвариантами классов, предусловиями, вообще с отслеживанием ошибок - ведь проще же их не делать. Ну что тут возразишь?
затем, что тебе надо единожды и явно указать какие данные являются некорректными. иначе корректный диапазон астрально/интуитивно проистекает из всех актов инициализации величины
Пожалуйста, излагай свои домыслы на тему, кто что делал или не делал и с кем/чем работал, в другом месте. Для отслеживания внутренних ошибок нормальные люди используют ассерты в наиболее замысловатых участках кода, а не if'ы лепят.
>что за данные? почему они кладутся «в точку»? похоже тут у Вас вырисовывается ошибка проектирования, либо Вы неточно описали задачу
При создании типа данных «точка» - это вообще не должно тебя интересовать: что, откуда. Твоя задача, как проектировщика, обеспечить такой интерфейс, чтобы клиент (тот, кто им пользуется) не мог привести объект в некорректное состояние. Если ты говоришь, что вот вы там все просто не умеете использовать мою замечательную структуру, надо было документацию читать, и не пришлось бы пару дней искать баг - то вот это и есть ошибка проектирования.
Это обычная проверка валидности введённых пользователем данных. Делается в одном месте, и сразу же выводится сообщение об ошибке. Зачем такую проверку надо вглубь запихивать, не очень понятно.
>Пожалуйста, излагай свои домыслы на тему, кто что делал или не делал и с кем/чем работал, в другом месте. Для отслеживания внутренних ошибок нормальные люди используют ассерты в наиболее замысловатых участках кода, а не if'ы лепят.
Ты вообще понимаешь о чем речь? Какая разница, как ты контролируешь корректность - if/return, if/throw, assert. Вопрос - размазать проверки по всему коду или вставить в единственный сеттер. «Замысловатые участки кода» - это для тех, кто научился ошибаться только в строго отведенных местах, а в остальной части программы усилием воли заставляет себя не делать их. И других заставляет так. И за изменениями в коде следит постоянно, чтобы отслеживать «замысловатости».
>Это обычная проверка валидности введённых пользователем данных. Делается в одном месте, и сразу же выводится сообщение об ошибке. Зачем такую проверку надо вглубь запихивать, не очень понятно.
Ты что, математически доказываешь корректность всех своих вычислений и поэтому проверки не ставишь? Или надеешься, что «уж дальше-то я не напартачу».
А если поля хитро связаны, и валидность проверяется для всего объекта целиком? А если из за этого невозможно независимо задать поля корректным образом (пытаешь менять одно поле, другое еще некорректно и получаешь через сеттер отлуп)? А как эти проперти работают во всяких выражениях (там из за них бывает мноооого глюков)?
Для проверки валидности тупо заводится метод bool check()
Если поля так уж нужно закрывать, закрываешь и вешаешь на каждое методы чтения/записи. Как вариант - открываешь поле для чтения через const reference и делаешь метод init согласованно устанавливающий нужные поля.
>Может аргументируешь столь многозначительный вывод? Мне очень интересно послушать!
Свойство объекта - это нормальное и естественное понятие в ООП, оно нисколько ни evil. Другое дело, что его можно употребить во зло и вместо улучшения инкапсуляции - понизить ее, вывернув кишки объекта, когда это совершенно не нужно. А в статье идет надуманное противопоставление интерфейса и свойств объекта. Огульный совет ОПу - «не используй аксессоры - оно инкапсуляцию нарушает» так же бесполезен, как и «не используй наследование - оно связность повышает».
на тот что могут попытаться списать отрицательную массу. а еще могут переместить отрицательную массу. и уже в трех местах тебе придется явно убедиться что масса объекта в любой операции неотрицательна - размазать проверку которую можно единожды и явно указать в одном месте.
> Есть класс Point { int x; int y; }. Как не нарушать инкапсуляцию, не пользоваться геттерами/сеттерами
Если класс Point представляет абстракцию точки в декартовых координатах, то методы int x(), void set_x(int) не нарушают инкапсуляцию и в принципе геттерами/сеттерами не являются - это часть абстракции декартовой точки.
В свою очередь реализация класса Point может использовать для представления, например, радиус и угол, а методы int x(), void set_x(int) останутся.