В чем преимущество создания виртуального частного метода в C ++?
Я заметил это в проекте C ++ с открытым исходным кодом:
class HTMLDocument : public Document, public CachedResourceClient {
private:
virtual bool childAllowed(Node*);
virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};
c++
polymorphism
access-specifier
silverburgh
источник
источник
Ответы:
Херб Саттер очень хорошо объяснил это здесь .
Правило №2: Предпочитайте делать виртуальные функции приватными.
Это позволяет производным классам переопределять функцию для настройки поведения по мере необходимости, без дальнейшего непосредственного раскрытия виртуальных функций, делая их доступными для вызова производными классами (что было бы возможно, если бы функции были просто защищены). Дело в том, что виртуальные функции существуют для настройки; если их также не нужно вызывать непосредственно из кода производных классов, нет необходимости делать их чем-либо, кроме закрытых
источник
super(...)
вызов родительского метода из переопределенной версии, который работает, даже если он частный?Если метод виртуальный, он может быть переопределен производными классами, даже если он частный. При вызове виртуального метода будет вызвана переопределенная версия.
(В отличие от Херба Саттера, которого цитирует Прасун Саурав в своем ответе, C ++ FAQ Lite не рекомендует использовать частные виртуальные машины , в основном потому, что это часто сбивает с толку людей.)
источник
Несмотря на все призывы объявить виртуального участника приватным, этот аргумент не выдерживает критики. Часто переопределение производного класса виртуальной функции должно вызывать версию базового класса. Не может, если заявлено
private
:Вы должны объявить метод базового класса
protected
.Затем вы должны воспользоваться уродливым приемом, указав в комментарии, что метод следует переопределить, но не вызывать.
Таким образом, рекомендация Херба Саттера № 3 ... Но лошадь все равно вышла из конюшни.
Когда вы объявляете что-
protected
то, вы неявно доверяете автору любого производного класса понимать и правильно использовать защищенные внутренние компоненты, точно так же, какfriend
объявление подразумевает более глубокое доверие дляprivate
членов.Пользователи, которые плохо себя ведут из-за нарушения этого доверия (например, получают ярлык «невежественный» из-за того, что не удосуживаются читать вашу документацию) должны винить только себя.
Обновление : у меня есть отзывы, в которых утверждается, что вы можете «связать» реализации виртуальных функций таким образом, используя частные виртуальные функции. Если так, то я бы обязательно это увидел.
Компиляторы C ++, которые я использую, определенно не позволяют реализации производного класса вызывать реализацию частного базового класса.
Если бы комитет C ++ ослабил «частный», чтобы разрешить этот конкретный доступ, я бы полностью сосредоточился на частных виртуальных функциях. В настоящее время нам все еще советуют запирать дверь сарая после кражи лошади.
источник
set_data
. Инструкцииm_data = ndata;
иcleanup();
поэтому могут считаться инвариантом, который должен соблюдаться для всех реализаций. Поэтому сделайтеcleanup()
не виртуальным и приватным. Добавьте вызов другого частного метода, который является виртуальным и точкой расширения вашего класса. Теперь вашим производным классамcleanup()
больше не нужно вызывать base , ваш код остается чистым, а ваш интерфейс трудно использовать неправильно.cleanup()
s в цепочке, аргумент разваливается. Или вы рекомендуете дополнительную виртуальную функцию для каждого потомка в цепочке? Ик. Даже Херб Саттер разрешил защищенные виртуальные функции как лазейку в своем руководстве № 3. В любом случае, без кода вы меня никогда не убедите.Я впервые столкнулся с этой концепцией, когда читал «Эффективный C ++» Скотта Мейерса, совет 35: Рассмотрите альтернативы виртуальным функциям. Я хотел бы сослаться на Скотта Майерса для других, которые могут быть заинтересованы.
Это часть шаблона метода шаблона с помощью идиомы невиртуального интерфейса : общедоступные методы не являются виртуальными; скорее они обертывают вызовы виртуальных методов, которые являются частными. Затем базовый класс может запускать логику до и после вызова частной виртуальной функции:
Я думаю, что это очень интересный шаблон проектирования, и я уверен, что вы видите, чем полезен добавленный элемент управления.
private
? Лучшая причина в том, что мы уже предоставилиpublic
метод облицовки.protected
так, чтобы я мог использовать этот метод для других интересных вещей? Я полагаю, это всегда будет зависеть от вашего дизайна и того, как, по вашему мнению, подходит базовый класс. Я бы сказал, что создатель производного класса должен сосредоточиться на реализации необходимой логики; обо всем остальном уже позаботились. Также есть вопрос инкапсуляции.С точки зрения C ++, полностью законно переопределить частный виртуальный метод, даже если вы не сможете вызвать его из своего класса. Это поддерживает дизайн, описанный выше.
источник
Я использую их, чтобы позволить производным классам «заполнять пробелы» для базового класса, не открывая такую дыру для конечных пользователей. Например, у меня есть объекты с высоким уровнем состояния, происходящие из общей базы, которая может реализовывать только 2/3 общего конечного автомата (производные классы предоставляют оставшуюся 1/3 в зависимости от аргумента шаблона, а база не может быть шаблоном для другие причины).
МНЕ НУЖНО иметь общий базовый класс, чтобы многие общедоступные API работали правильно (я использую вариативные шаблоны), но я не могу позволить этому объекту выйти в свет. Хуже того, если я оставлю кратеры в конечном автомате - в форме чистых виртуальных функций - где угодно, кроме «Private», я разрешаю умному или невежественному пользователю, производному от одного из его дочерних классов, переопределить методы, к которым пользователи никогда не должны прикасаться. Итак, я вложил "мозги" конечного автомата в ЧАСТНЫЕ виртуальные функции. Затем непосредственные дочерние элементы базового класса заполняют пробелы в своих НЕвиртуальных переопределениях, и пользователи могут безопасно использовать полученные объекты или создавать свои собственные производные классы, не беспокоясь о нарушении работы конечного автомата.
Что касается аргумента, что вам не следует ИМЕТЬ публичные виртуальные методы, я говорю BS. Пользователи могут неправильно переопределять частные виртуальные машины так же легко, как и публичные - в конце концов, они определяют новые классы. Если публика не должна изменять данный API, не делайте его ВООБЩЕ в общедоступных объектах.
источник