Следует ли вам когда-либо использовать защищенные переменные-члены? - PullRequest
92 голосов
/ 31 августа 2008

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

Ответы [ 10 ]

70 голосов
/ 31 августа 2008

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

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

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

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

30 голосов
/ 31 августа 2008

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

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

28 голосов
/ 01 сентября 2008

Как правило, если что-то не является преднамеренно открытым, я делаю это частным.

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

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

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

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

Единственными реальными исключениями из этого являются случаи, когда вы отправляете двоичные DLL в виде черного ящика третьим лицам. Он состоит в основном из Microsoft, поставщиков «Custom DataGrid Control» и, возможно, нескольких других крупных приложений, которые поставляются с библиотеками расширяемости. Если вы не относитесь к этой категории, не стоит тратить время / усилия, чтобы беспокоиться о подобных вещах.

7 голосов
/ 10 декабря 2008

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

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

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

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

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

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

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

6 голосов
/ 15 мая 2013

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

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

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

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

Как пример:

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

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

6 голосов
/ 10 февраля 2010

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

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

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

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

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

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

4 голосов
/ 12 октября 2008

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

Но у меня есть один хороший пример: допустим, вы можете использовать какой-то универсальный контейнер. Он имеет внутреннюю реализацию и внутренние средства доступа. Но вам нужно предложить как минимум 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. */ }

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

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

3 голосов
/ 01 сентября 2008

Короче, да.

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

2 голосов
/ 15 апреля 2013

Просто для записи, под пунктом 24 «Исключительного C ++» в одной из сносок Саттер идет «Вы бы никогда не написали класс, который имеет открытую или защищенную переменную-член. Верно?

2 голосов
/ 31 августа 2008

Для получения подробной информации о модификаторах доступа .Net перейдите сюда

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...