Как препятствовать тому, чтобы производный класс обнародовал частную/защищенную виртуальную функцию?

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

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

class A {
        protected:
        virtual void none() { return; }
};

class B: public A {
        public:
        void none() { return; }
};

g++ -c -Wall -pedantic file.cpp скомпилированный без ошибки. Добавление -Weffc++ дал предупреждение: warning: ‘class A’ has virtual functions and accessible non-virtual destructor, который имеет смысл. После добавления виртуального деструктора нет никакого предупреждения. Таким образом, нет никакого предупреждения для этого easy-to-go-wrong случая.

5
задан Community 23 May 2017 в 11:48
поделиться

5 ответов

Как сказал Бьярне, контроль доступа в C++ предназначен для защиты от Мерфи, а не от Макиавелли. То же самое верно и в целом - его функции предназначены для защиты от несчастных случаев, а не от людей, намеренно делающих что-то не так.

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

Правка: На самом деле это вовсе не "аргумент" - это просто указание на основу, на которой были приняты решения. Так как моя копия D&E не отвечает на предыдущий вопрос, я напечатаю немного больше, если она здесь1:

Важнее разрешить полезную функцию, чем предотвратить каждую неправильное использование: Вы можете писать плохие программы. на любом языке. Важно минимизировать вероятность случайности неправильное использование функций, и много усилий был потрачен на то, чтобы убедиться, что поведение конструкций C++ по умолчанию либо разумно, либо ведет к ошибки компиляции. Например, по по умолчанию все типы аргументов функции проверяются... даже по отдельности границы компиляции -- и по по умолчанию все члены класса являются приватными. Однако, системное программирование язык не может помешать определённому программист не сломал систему так на проектирование лучше потратить предоставление возможностей для хорошего письма программы чем предотвратить неизбежные плохие. Чем дольше бегать, программисты, кажется, учатся. Этот это вариант старого C "доверяйте слоган "программист". Различный тип правила проверки и контроля доступа существуют для того, чтобы позволить провайдеру класса четко сформулировать, что ожидается от пользователей, для защиты от несчастных случаев. Эти правила не предназначены для защита от умышленного нарушение (§2.10).

В § 2.10 он, среди прочего, говорит:

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

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

1§4.3, pgs. 115, 116.

12
ответ дан 18 December 2019 в 07:29
поделиться

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

2
ответ дан 18 December 2019 в 07:29
поделиться

Вы не можете. «Виртуальность» функции и типа доступа - две разные несвязанные концепции.

2
ответ дан 18 December 2019 в 07:29
поделиться

Контроль доступа в C ++, возможно, не делает то, что вы хотите. Он не предназначен для обеспечения соблюдения ограничений в стиле DRM, чтобы остановить вы делиться доступом. Если A имеет доступ к B, то A может вызывать B и использовать результат для любых целей, включая возврат его к другому вызывающему абонеру, у которого нет доступа к B.

. Проблема, которая обсуждается в статье, которую вы ссылаетесь на ISN ' T О нас намеренно или злонамеренно поделившись B. Это о том, что произойдет, если вы поместите публичную виртуальную функцию в опубликованном интерфейсе, а затем попытаетесь изменить класс, чтобы он использовал свои рекомендуемые шаблоны метода шаблона, включая частные виртуальные функции. Детские классы написали публичные переопределения виртуальной функции, поэтому вы больше не можете отделить двух проблем (доступа и виртуальность), не модифицируя все детские классы. То, как я его прочитал, в статье предлагается решение проблемы, которую он представляет, и что решение «никогда не вступает в виртуальные функции в первую очередь».

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

Причина, по которой это не решает вашу проблему, состоит в том, что они не рассматривали вашу проблему.

2
ответ дан 18 December 2019 в 07:29
поделиться

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

protected:
class ProtectedToken { virtual ~ProtectedToken() { } };
virtual void my_tough_cookie(int arg,
  ProtectedToken const &tok = ProtectedToken() ) {
    assert ( typeid( tok ) == typeid( ProtectedToken ) );
    …
}

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

Редактировать: BAH, это не работает. Даже если это сделало, вы могли бы сделать публики: использование базы :: ProtectedToken и поражать защиту таким образом. Еще 15 минут моей жизни впустую ...

1
ответ дан 18 December 2019 в 07:29
поделиться
Другие вопросы по тегам:

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