Почему виртуальная функция должна быть закрытой?

Я только что заметил это в некотором коде:

class Foo {
[...]
private:
    virtual void Bar() = 0;
[...]
}

Есть ли в этом какая-то цель?

(Я пытаюсь перенести некоторый код из VS в G++, и это привлекло мое внимание)

8 ответов

Решение

Посмотрите эту статью Херба Саттера о том, почему вы хотите сделать такую ​​вещь.

ISO C++ 2003 явно позволяет это:

В п. 10.3 ничего не говорится о спецификаторе доступа и даже содержится сноска во втором предложении, в которой говорится в контексте переопределений виртуальных функций:

[...] Контроль доступа (пункт 11) не учитывается при определении переопределения.

Кодекс полностью легален.

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

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

Для относительно плохого примера:)

класс RecordFile
{
    общественности:
       RecordFile(const std::string &filename);

       пустой процесс (const Record &rec)
       {
           // Вызов функции производного класса для фильтрации
           // записывает производный экземпляр этого класса
           // не волнует
           if (filterRecord(rec))    
           {
               writeRecordToFile(ЗАП);           
           }
       };

    частный:
       // Возвращает true, если запись важна
       // и должны быть сохранены
       виртуальный bool filterRecord (const Record & rec) = 0;

       void writeRecordToFile (const Record & rec);
};

Я приведу краткое объяснение из замечательного C++ FAQ Lite, которое хорошо подытоживает:

[23.4] Когда кто-то должен использовать частные виртуалы?

Почти никогда.

Защищенные виртуальные системы в порядке, но частные виртуальные, как правило, являются чистым убытком. Причина: частные виртуальные системы сбивают с толку новых программистов на C++, а путаница увеличивает стоимость, задерживает график и снижает риск.

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

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


Тем временем C++ FAQ Lite был обновлен:

Кстати, большинство начинающих программистов на C++ смущает, что частные виртуальные машины могут быть переопределены, не говоря уже о том, что они действительны. Нас всех учили, что частные члены в базовом классе недоступны в классах, производных от него, и это правильно. Однако эта недоступность производным классом не имеет ничего общего с механизмом виртуального вызова, который относится к производному классу. Поскольку это может запутать новичков, в FAQ по С ++ ранее рекомендовалось использовать защищенные виртуальные, а не частные виртуальные. Однако частный виртуальный подход в настоящее время достаточно распространен, так что путаница между новичками не так важна.

Обычный "академический" ответ таков: спецификаторы доступа и виртуальность ортогональны - одно не влияет на другое.

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

Это чисто виртуальная функция. Любая конечная реализация, полученная из "Foo", ДОЛЖНА реализовывать функцию "Bar".

Это делает функцию чисто виртуальной, а не виртуальной.

Реализация по умолчанию не предусмотрена, и предполагается, что реализация функции должна быть указана наследующим классом. Это может быть отменено, однако.

Иногда вы видите законченные классы, в которых все функции-члены указываются как чисто виртуальные таким образом.

Это абстрактные базовые классы, иногда называемые интерфейсными классами, и разработчик ABC говорит вам: "Теперь я представляю, как эта функциональность будет реализована для всех специализаций этого базового класса. Но вы должны иметь все они определены для вашей специализации, и вы знаете, как должен вести себя ваш объект ".

Изменить: Ой, только что заметил тот факт, что чисто виртуальная функция члена является частной. (Спасибо Майкл) Это немного меняет дело.

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

Поэтому некоторая публичная функция в Foo вызывает функцию Bar внутри Foo, и она полагается на то, что вы предоставите специализированную реализацию функции Bar для вашего конкретного случая.

Скотт Мейерс называет это "реализованным в терминах".

Кстати, просто посмеиваясь над количеством ответов, которые были быстро удалены людьми, которые также не увидели "мелкий шрифт" в вопросе! (-:

НТН

веселит,

Похоже, единственная цель - предоставить общий интерфейс.

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

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

Другие вопросы по тегам