Эти два класса нарушают инкапсуляцию?

class X
{
protected:
    void protectedFunction() { cout << "I am protected" ; }
};

class Y : public X
{
public:
    using X::protectedFunction;
};

int main()
{
    Y y1;
    y1.protectedFunction();
}

Таким образом, я могу выставить одну из функций базового класса.

  1. Разве это не нарушает принцип инкапсуляции?
  2. Существует ли определенная причина относительно того, почему это находится в стандарте?
  3. Есть ли какое-либо использование этого или будет измененным в новом стандарте?
  4. Там какие-либо нерешенные вопросы связаны с этим в стандарте?
9
задан Jamal 23 May 2014 в 01:26
поделиться

10 ответов

Как насчет использования торнадо ? Я попробовал демо чата приложение Торнадо. А также Tornado утверждает, что имеет лучшую производительность, чем джанго.

Дайте мне знать ваши мысли.

-121--3140655-

Документы содержат довольно длинное объяснение того, почему Apple не хочет, чтобы вы делали это, и почему они явно не поддерживают его в Получение изменяемых объектов . Резюме:

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

Я нахожу их пример NSView самым простым для понимания, и он иллюстрирует основную проблему какао. У вас есть NSMuterArray с именем «elements», который вы хотите представить как массив, но не хотите, чтобы вызывающие абоненты связывались с ним. Есть несколько вариантов:

  1. Выставьте NSMuterArray как NSAray.
  2. Всегда создавать несменяемую копию при запросе
  3. Сохранять элементы как NSAray и создавать новый массив каждый раз, когда он мутирует.

Я сделал все это в различные точки. # 1 - самое простое и быстрое решение. Это также опасно, так как массив может мутировать за спиной звонящего. Но Apple указывает на то, что они делают в некоторых случаях (обратите внимание на предупреждение для -subviews в NSView). Я могу подтвердить, что, хотя # 2 и # 3 гораздо безопаснее, они могут создавать серьезные проблемы с производительностью, что, вероятно, и является причиной того, что Apple решила не использовать их на часто доступных членах, таких как -subviews.

Суть всего этого в том, что если вы используете # 1, то самоанализ введет вас в заблуждение. В качестве NSAray используется приведение NSMuterArray, и самоанализ указывает на возможность его изменения (самоанализ не имеет пути знать об обратном). Но вы не должны его мутировать. Только проверка типа компиляции может вам это сказать, и это единственное, чему вы можете доверять.

Исправлением для этого была бы какая-то быстрая неизменяемая версия изменяемой структуры данных при копировании на запись. Таким образом, # 2 можно было бы сделать с достойной производительностью. Я могу представить себе изменения в кластере NSAray, которые позволили бы это сделать, но его сегодня нет в какао (и он может повлиять на производительность NSAray в обычном случае, что делает его не стартером). Даже если бы он был у нас, там, вероятно, слишком много кода, который полагается на текущее поведение, чтобы когда-либо позволить самоанализу мутабельности быть доверенным.

-121--3815238-

Да, и поэтому защита получила значительную часть критики.

Бьярне Строуструп, создатель C++, сожалеет об этом в своей превосходной книге «Дизайн и эволюция C++:

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

12
ответ дан 4 December 2019 в 06:00
поделиться

Вы сделали это самостоятельно.
Вы можете написать

class Y : public X
{
public:
    void doA()
    {
       protectedFunction();
    }
};

int main()
{
    Y y1;
    y1.doA(); 
}

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

18
ответ дан 4 December 2019 в 06:00
поделиться

Я думаю, что он был сам stroustrup, который сказал, что инкапсуляция и функции целостности данных, встроенные в C ++, предназначены для того, чтобы честно были честными людьми, чтобы не остановить преступников.

11
ответ дан 4 December 2019 в 06:00
поделиться

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

Если бы вы могли сделать это с помощью частного методом, был бы проблема ... (Отредактировано, чтобы быть немного понятным).

3
ответ дан 4 December 2019 в 06:00
поделиться

Дизайнер класса должен знать, что объявление функции элементов или переменной (хотя все переменные должны быть частными, действительно), поскольку защищена в основном такая же, как объявление об этом общественности (поскольку вы прошлите легко получить доступ к защищенным вещам). Имея в виду, заботиться о том, чтобы быть приняты при внедрении этих функций в базовом классе для учета «неожиданного» использования. Это не нарушение инкапсуляции, потому что вы можете получить доступ к нему и разоблачить его.

Защищенный - это просто более сложный способ объявления чего-либо публичного!

1
ответ дан 4 December 2019 в 06:00
поделиться

Нет, я не вижу проблему.

вместо с использованием , используя , вы могли бы сделать это:

class X
{
protected:
    void protectedFunction() { cout << "i am protected" ; }
};

class Y : public X
{
public:
    void protectedFunction() { X::protectedFunction(); }
};

Любой класс может принять любого элемента, который виден ему, и решите публично разоблачить. Это может быть плохой класс дизайна для этого, но это, конечно, не недостаток на языке. Весь смысл в частных или защищенных членах является то, что сам класс должен решить, кто должен получить доступ к члену. И если класс решает: «Я собираюсь дать весь мир доступ», то то есть как класс спроектирован.

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

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

1
ответ дан 4 December 2019 в 06:00
поделиться

в C ++ даже личный модификатор не гарантирует инкапсуляцию. Никто не может остановить вас от стрельбы себя в ногу.

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

Здесь смешной пример из статьи трва.

злая макрос магистра

#define protected public // illegal
#include "X.h"
//...
X y1;
y1.protectedFunction();
2
ответ дан 4 December 2019 в 06:00
поделиться

На языковой точке зрения, это не более нарушение инкапсуляции, чем создание метода делегата в производном объекте:

class Y : public X
{
public:
    void protectedFunction() {
       X::protectedFunction();
    }
};

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

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

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

2
ответ дан 4 December 2019 в 06:00
поделиться

Нет.

Чтобы использовать общедоступный метод, у вас должен быть экземпляр y , это не будет работать:

int main()
{
    X y1;
    y1.protectedFunction();
}

Если y в своем новом определении обнародует новый интерфейс, он находится в том, что Y. X все еще защищен.

2
ответ дан 4 December 2019 в 06:00
поделиться

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

Я бы спросил: «Какова была смысл охраняемого метода в первую очередь?» Был ли это метод, который должен вызывать только подклассы, или это способ, которым подклассы должны переопределять? Однако это может быть метод, который не ожидается в общем базовом классе, но, возможно, ожидается в подклассе. Клиенту базового класса они никогда не знали о том, что охраняемый метод. Создатель подкласса решил расширить контракт, и теперь, когда защищенный метод является публичным. Вопрос действительно должен быть не C ++ позволяет ему, но правильно ли у вас класс, контракт и будущие сопровождающие. Уверен, что это может быть плохой запах, но на самом деле вам нужно сделать его правильным для использования в применении.

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

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

1
ответ дан 4 December 2019 в 06:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: