Get/Set в мире С++, faux-pas?
Я замечаю, что get/set не является способом С++, насколько я могу судить, глядя на boost/stl и даже на чтение статей некоторых из лучших экспертов на С++.
Кто-нибудь использует get/set в своем дизайне класса С++, и может ли кто-нибудь предложить эмпирическое правило о том, где, если эта парадигма вообще не принадлежит миру С++?
Он, очевидно, очень популярен в Java и имитируется С#, используя синтаксический сахар.
EDIT:
Хорошо прочитав об этом в одной из ссылок, приведенных в ответе ниже, я натолкнулся хотя бы на один аргумент для того, чтобы аксесуары поля участника имели то же имя, что и поле члена. А именно, что вы можете просто открыть поле члена как общедоступное и вместо этого сделать его экземпляром класса, а затем перегрузить оператор(). Используя set/get, вы заставите клиентов не только перекомпилировать, но и фактически изменить свой код.
Не уверен, что мне нравится эта идея, кажется мне слишком мелкой, но более подробная информация здесь:
С++ убил Getter/Setter
Ответы
Ответ 1
С++ не имеет таких свойств, как С#. В именах можно писать методы с "get" и "set", но они автоматически не создают свойства. Так хорошо ли использовать методы get и set?
Использование методов get и set в С++ не плохо для доступа к свойствам класса. STL и boost (на которые повлиял STL) просто выбрали один дизайн - он идеально подходит для дизайна вашего класса.
В моей работе мы используем get и set. Причина в том, что он позволяет писать парсеры для автоматического переноса классов С++ с помощью других интерфейсов - ActiveX,.NET, LabVIEW, Python и т.д. При использовании Visual Studio intellisence (и аналогичных технологий на других IDE), Я нахожу, что использование методов get и set делает поиск того, что мне было проще. Таким образом, есть моменты, когда полезно использовать методы get и set.
Самое главное - выбрать стандарт стиля кода для вашей библиотеки и быть в соответствии с ним.
Ответ 2
Инкапсуляция представляет собой концепцию ООП и применяется ко всем языкам ООП. Публичные данные будут разбиты на инкапсуляцию. Это может быть хорошо, если у вас очень простой объект, который не нуждается в инкапсуляции, однако эти ситуации являются исключением, и как только вы примете решение, его трудно будет вернуться и отменить.
Для большинства объектов вам понадобятся геттеры и сеттеры, но вы всегда должны учитывать, как объект будет фактически использоваться при их написании. Boost и STL полны геттеров и сеттеров, они просто не используют имена "get" и "set", вместо этого они используют имена типа "длина", "конец", "резерв", "емкость" и т.д. Причина, по которой они не используйте слова get или set, потому что эти функции служат цели больше, чем просто установка значения в объекте.
Ваши получатели и сеттеры должны делать то же самое. Вместо того, чтобы разрабатывать интерфейс с точки зрения того, как работает объект, вы должны определить его с точки зрения того, как он будет использоваться.
Ответ 3
Вы можете определенно использовать accessors в С++. Это хорошая статья о том, чтобы придумать хорошие схемы доступа. Связанная статья также показывает вам простой класс вспомогательного помощника мета-помощника, который поможет вам определить эти интеллектуальные аксессоры тривиально.
Ответ 4
В общем случае методы get/set подрывают инкапсуляцию, выставляя внутреннюю реализацию и состояние. Если вы обнаружите, что используете get/set для каждого отдельного фрагмента данных в вашем классе, скорее всего, лучше просто сделать его простым агрегатным типом только с общедоступными данными и без методов.
Я действительно не покупаю, что get/set облегчает работу, например, делает ваш класс потокобезопасным, потому что ограниченная синхронизация, которую вы можете предоставить, защищает от всех неправильных видов условий гонки.
Ответ 5
Я не знаю, рекомендовал ли он использование или нет, но я регулярно использую функции get/set в своих классах С++, и я пишу код С++ уже более двух десятилетий. Я никогда не смотрел на Java или С#, поэтому я не привык к этим языкам.
Ответ 6
У меня, как правило, есть геттеры и сеттеры, я просто не называю их "getX и" setX ", обычно я буду делать что-то вроде этого, например:
int x = o->x() // getter
o->setX(5); // setter
Я обнаружил, что наличие getter просто имя "свойство" просто читается лучше.
Ответ 7
Я почти всегда использую методы get/set, главным образом потому, что вы можете установить точки останова на них и выяснить, где установлен элемент данных (или доступ, хотя это менее распространено). Кроме того, вы можете добавлять утверждения отладки внутри процедуры setter (и процедуры getter, хотя это менее полезно), чтобы убедиться, что объект находится в допустимом состоянии при установке значения.
Это также полезно, если вы создаете подкласс; иногда подкласс хочет сделать некоторые вычисления, а не просто перенастроить значение. Создание виртуальной процедуры getter, а затем ее переопределение в подклассе упрощает процесс.
Ответ 8
Будет немного дидактическим здесь...
Для аксессуаров есть два аспекта:
- Работа с синтаксисом языка
- Коммуникационные намерения
Также существует и третий аспект, который часто игнорируется, и это связано с грамотностью обработки изменений. Моя статья, на которую вы ссылаетесь, затрагивает этот последний пункт, но ничего не говорит о двух других.
Чтобы попытаться обработать изменения в синтаксисе используемого вами языка, в основном это техническая проблема, которая поддается нескольким советам, сложенным вместе на веб-странице с небольшим количеством кода для резервного копирования.
Самый сложный аспект - это передача намерения, и способ сделать это - придерживаться идиом языка. К сожалению, в С++ синтаксис немного мешает, поэтому у нас есть такие вещи, как .size() для коллекций и .first и .second по парам. Они все аксессоры, но синтаксис изменяется в зависимости от реализации - ouch.
Теперь, eJames рассказывает о публичных участниках, нарушающих инкапсуляцию. Независимо от того, является ли участник общедоступным или нет, он не имеет никакого отношения к инкапсуляции. Инкапсуляция - это продукт дизайна объектов и элементов управления, доступных дизайнеру класса на языке, который они используют. Это то, что я изучил более подробно в "Encapsulation is Good Thing ™" (этот сайт еще не позволит мне добавить ссылку, но я думаю, что это не слишком сложно для Google).
Что нам остается, так это то, что в С++ производный атрибут должен использовать синтаксис вызова метода. Неизлученное поле не обязательно, но может выбрать, если вы этого пожелаете. Если вы используете синтаксис вызова метода, вы должны сами написать метод обертки. Не сложно, но это, безусловно, добавляет к счету строк. Я попытался показать, как использовать язык шаблонов С++ для абстрагирования кода доступа. Это не совсем успешно, но он справляется со многими вариантами использования.
Что касается того, следует ли использовать аксессоры или нет, проблема в том, что синтаксис С++ заставляет разграничение между доступом простого элемента и доступом к методу на нас как разработчиков. Это раздражает, но у нас есть некоторые инструменты, чтобы что-то сделать с этим.
Как разработчик библиотеки, я обнаружил, что всегда использование синтаксиса вызова метода помогает мне создавать более надежные API-интерфейсы, потому что, если я нахожу, что хочу заменить простой элемент чем-то более сложным, это дает мне больше опций, которые не требуют достаточно синтаксиса. Помните, что я мог бы абстрагироваться другим способом и сделать "функцию" похожим на ценность с помощью подходящего использования операторов трансляции и операторов-ассигнаторов. Возможно, я попробую это и посмотрю, как я к этому отношусь:)
Ответ 9
Мой опыт связан с С++ и Java, хотя в настоящее время я работаю в PHP. Мои общие правила, которые я использую для PHP и С++:
-
Если вам нужно, чтобы переменная-член читалась вне класса, но не была доступна для записи: используйте только getVariableX().
-
Если вы хотите, чтобы переменные-члены изменялись/читались вне класса, но для них требуется дополнительная работа до/после изменения их значений: используйте setVariableX() и getVariableX().
-
Если переменная-член может быть изменена вне класса, а методы set/get просто будут просто присваиваться: просто сделайте переменную общедоступной, так как вы все равно будете делать с set/gets (только в более запутанным образом).
Обратите внимание, что если ваши методы get и set делают намного больше, чем тривиально получать и настраивать, то вам, вероятно, следует переименовать их, чтобы более точно описать их функцию.
Ответ 10
Я использую только геттеры/сеттеры, когда альтернативы нет. Когда я могу, я использую этот шаблон (не в том смысле, что это хорошая практика, но в том смысле, что я делаю это последовательно): Изменение свойства не влияет на поведение объекта, пока оно действительно не понадобится. Например:
myWnd->Title = "hello"; // not a setter, just a LPCSTR member
myWnd->Title = "world";
myWnd->ShowWindow(); // perhaps updates a WNDCLASS structure
// and other complicated things that
// the user of the class doesn't want to know
Я знаю, что это означает, что мне придется написать некоторые надуманные частные методы для обновления внутренних состояний объектов, но если эти усилия необходимы, чтобы скрыть сложность для пользователя класса, мне придется это сделать.
Ответ 11
Я собираюсь сделать некоторые догадки.
- C даже не имел возможности getters/seters, поэтому была привычка использовать прямой доступ к членам, как в структуре. Привычка застряла на С++.
- C/С++ всегда предпочитали скорость, и если бы существовала какая-либо возможность старого компилятора, который не был бы правильно встроен, у получателя/сеттера был бы штраф за скорость.
Ни одна из этих причин не является веской.
Ответ 12
Даже tho С++ не поддерживает атрибуты свойств, имитируя их, мы не только улучшаем читаемость или предоставляем инкапсуляцию, но и предоставляем механизм управления для установки значения переменной или получаем вычисляемое значение для переменной. Так что это конечная цель аксессуаров. Чтобы достичь этих целей, язык необходим для непосредственного доступа к аксессуарам. Период.