Должны ли вы когда-либо использовать защищенные переменные-члены?

Должны ли вы когда-либо использовать защищенные переменные-члены? Каковы преимущества и проблемы, которые могут возникнуть?

Ответ 1

Должны ли вы когда-либо использовать защищенные переменные-члены?

В зависимости от того, насколько вы сообразите о скрытии состояния.

  • Если вы не хотите утечки внутреннего состояния, то объявление всех ваших переменных-членов является способом перехода.
  • Если вам не все равно, что подклассы могут получить доступ к внутреннему состоянию, тогда защита будет достаточно хороша.

Если разработчик приходит и подклассифицирует ваш класс, он может испортить его, потому что он не понимает его полностью. С частными членами, помимо публичного интерфейса, они не могут видеть конкретные детали реализации, как это делается, что дает вам гибкость в ее изменении позже.

Ответ 2

В наше время общее ощущение состоит в том, что они вызывают неоправданную связь между производными классами и их основами.

У них нет особого преимущества над защищенными методами/свойствами (когда-то они могли иметь небольшое преимущество в производительности), и они также использовались больше в эпоху, когда очень глубокое наследование было в моде, чего не было момент.

Ответ 3

Как правило, если что-то не намеренно задумывается как общедоступное, я делаю его частным.

Если возникает ситуация, когда мне нужен доступ к этой частной переменной или методу из производного класса, я изменяю ее из частного в защищенный.

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

Я бы сказал, что это хорошо (и, вероятно, лучший способ сделать это) для большинства разработчиков.

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

Единственными реальными исключениями для этого являются, если вы занимаетесь отправкой бинарной dll в форме черного ящика третьим лицам. Это в основном состоит из Microsoft, тех поставщиков CustomGrid Control и, возможно, нескольких других крупных приложений, которые поставляются с библиотеками расширяемости. Если вы не находитесь в этой категории, не стоит тратить время/усилия, чтобы беспокоиться об этом.

Ответ 4

В общем, я бы сохранил ваши защищенные переменные-члены в редком случае, когда у вас есть полный контроль над кодом, который их использует. Если вы создаете публичный API, я бы сказал, никогда. Ниже мы будем ссылаться на переменную-член как на "свойство" объекта.

Здесь, что ваш суперкласс не может сделать после создания переменной-члена, а не private-with-accessors:

  • лениво создавать значение "на лету", когда свойство читается. Если вы добавите защищенный метод getter, вы можете лениво создать значение и передать его обратно.

  • знать, когда свойство было изменено или удалено. Это может привести к ошибкам, когда суперкласс делает предположения о состоянии этой переменной. Создание защищенного метода setter для переменной сохраняет этот контроль.

  • Установите точку останова или добавьте отладочный вывод, когда переменная читается или записывается.

  • Переименуйте эту переменную-член, не просматривая весь код, который может ее использовать.

В общем, я думаю, что это был бы редкий случай, который я бы рекомендовал сделать защищенной переменной-членом. Вам лучше потратить несколько минут, разоблачая свойство через getters/seters, чем через несколько часов, отслеживая ошибку в каком-то другом коде, который модифицировал защищенную переменную. Не только это, но вы застрахованы от добавления будущей функциональности (например, ленивой загрузки) без нарушения зависимого кода. Это сложнее сделать это позже, чем сделать это сейчас.

Ответ 5

На уровне проектирования может быть целесообразно использовать защищенное свойство, но для реализации я не вижу преимущества в сопоставлении этого с защищенной переменной-членом, а не с методами accessor/mutator.

Защищенные переменные-члены имеют существенные недостатки, поскольку они позволяют клиенту-коду (подклассу) получить доступ к внутреннему состоянию класса базового класса. Это не позволяет базовому классу эффективно поддерживать свои инварианты.

По той же причине защищенные переменные-члены также делают запись безопасного многопоточного кода значительно сложнее, если не гарантируется постоянная или ограниченная одним потоком.

Методы Accessor/mutator обеспечивают значительно большую стабильность API и гибкость реализации при обслуживании.

Кроме того, если вы - пурист OO, объекты взаимодействуют/обмениваются сообщениями, не считая/устанавливая состояние.

В свою очередь, они предлагают очень мало преимуществ. Я не обязательно удалял их из кода другого, но сам не использую их.

Ответ 6

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

Например, если у меня есть класс, определяющий ширину и высоту визуализируемого объекта, и я защищаю эти переменные, тогда я не могу делать никаких предположений относительно (например), соотношения сторон.

Критически, я никогда не смогу сделать эти предположения в любой момент с момента выпуска кода в виде библиотеки, так как даже если я обновляю свои сеттеры для поддержания пропорций, я не гарантирую, что переменные устанавливаются через сеттеры или доступ через геттеры в существующем коде.

Кроме того, какой-либо подкласс моего класса может выбрать эту гарантию, поскольку они не могут принудительно выполнять значения переменных, , даже если это все точки их подкласса.

В качестве примера:

  • У меня есть класс прямоугольника с шириной и высотой, который хранится как защищенные переменные.
  • Очевидный подкласс (в моем контексте) - это класс "DisplayedRectangle", где единственное отличие заключается в том, что я ограничиваю значения ширины и высоты допустимыми значениями для графического отображения.
  • Но это невозможно сейчас, так как мой класс DisplayedRectangle не может по-настоящему ограничивать эти значения, поскольку любой его подкласс может переопределять значения напрямую, но все еще рассматривается как отображаемыйRectangle.

Ограничивая приватные переменные, я могу затем выполнить поведение, которое я хочу, через сеттеры или получатели.

Ответ 7

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

Но у меня есть один хороший пример: пусть говорят, что вы можете использовать какой-то общий контейнер. Он имеет внутреннюю реализацию и внутренние аксессоры. Но вам нужно предложить как минимум 3 открытых доступа к своим данным: map, hash_map, vector-like. Тогда у вас есть что-то вроде:

template <typename T, typename TContainer>
class Base
{
   // etc.
   protected
   TContainer container ;
}

template <typename Key, typename T>
class DerivedMap     : public Base<T, std::map<Key, T> >      { /* etc. */ }

template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }

template <typename T>
class DerivedVector  : public Base<T, std::vector<T> >        { /* etc. */ }

Я использовал этот код меньше месяца назад (так что код из памяти). После некоторого размышления я считаю, что, хотя общий базовый контейнер должен быть абстрактным классом, даже если он может жить достаточно хорошо, потому что использование непосредственно базы будет такой болью, это должно быть запрещено.

Сводка Таким образом, вы защитили данные, используемые производным классом. Тем не менее, мы должны принять во внимание тот факт, что базовый класс должен быть абстрактным.

Ответ 8

Короче говоря, да.

Защищенные переменные-члены допускают доступ к переменной из любых подклассов, а также для любых классов в одном пакете. Это может быть очень полезно, особенно для данных только для чтения. Я не верю, что они когда-либо необходимы, потому что любое использование защищенной переменной-члена может быть реплицировано с использованием переменной частного члена и нескольких геттеров и сеттеров.

Ответ 9

Подробнее о модификаторах доступа .Net перейти сюда

Нет никаких реальных преимуществ или недостатков защищенных переменных-членов, это вопрос о том, что вам нужно в вашей конкретной ситуации. В общем случае принято считать, что переменные-члены являются частными и разрешают внешний доступ через свойства. Кроме того, некоторые инструменты (например, некоторые O/R-mappers) ожидают, что данные объекта будут представлены свойствами и не будут распознавать общедоступные или защищенные переменные-члены. Но если вы знаете, что хотите, чтобы ваши подклассы (и ТОЛЬКО ваши подклассы) обращались к определенной переменной, нет причин не объявлять ее защищенной.

Ответ 10

Только для записи, в пункте 24 "Исключительного С++", в одной из сносок Саттер идет "вы никогда не напишете класс, который имеет общедоступную или защищенную переменную-члена. right? (Независимо от плохого примера, установленного некоторыми библиотеками.)"