25

Я просто заметил это в какой-то код:Зачем нужна виртуальная функция?

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

ли это какой-либо цели?

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

+1

Прошу прощения, какая часть вас смущает? – drxzcl

+20

«Частная» часть. – liori

+8

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

ответ

23

См this Herb Sutter article, почему вы хотели бы сделать такую ​​вещь

+8

лучше перефразировать или подытожить ответ своими словами. распределенный характер ftw. ;) – wilhelmtell

+8

Нет, лучше нет. Я не знаю, что такое педагогические навыки Грега, но я сомневаюсь, что они лучше, чем Саттерс. – 2009-07-15 21:01:48

+2

Итак, в основном, нужно указать шаблон шаблона шаблона? Так что производный класс может переопределить метод, но только базовый класс может его назвать? Я предполагаю, что это полезно, но поскольку производный класс может просто создать свой собственный внутренний метод и вызвать его из Bar(), я не уверен, что это соответствует более чем предположению. – jprete

2

Это чисто виртуальная функция. Любая окончательная реализация, которая держится от «Foo», ДОЛЖНА реализовать функцию «Бар».

+0

кроме отмечен как «частный». ОП не сделал свой вопрос ясным, и мне пришлось взглянуть на него на секунду или два, прежде чем я понял, что это было отмечено как личное, так что +1, чтобы отрицать -1. –

1

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

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

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

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

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

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

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

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

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

НТН

веселит,

0

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

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

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

5

Я собираюсь процитировать краткое объяснение от великого C++ FAQ Lite который суммирует это хорошо:

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

Практически никогда.

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

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

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


C++ FAQ Lite был обновлен в то же время:

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

+2

Я думаю, что Клайн и Саттер не согласны здесь. См. Ссылку в ответе Грега Роджерса. –

+5

Вот почему мне не нравятся часто задаваемые вопросы по C++, их полные мнения, которые когда-то были просто глупыми, и идут вразрез с лучшими практиками, как это определено некоторыми из ведущих мыслителей в этой области. См. Ответ Herb Sutters для гораздо лучшего объяснения, которое имеет опирающееся мнение. –

+0

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

5

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

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

+0

Если спецификаторы доступа и виртуальность ортогональны, то почему http://ideone.com/JjbVOP не удается выполнить компиляцию? Вызов виртуальной функции разрешен во время выполнения, а не во время компиляции, чем я ошибался в своей программе? Невозможно ли переопределить защищенные виртуальные методы базового класса классом Derived? – Destructor

+0

@Destructor Ошибка компиляции заключается в том, что вы пытаетесь вызвать защищенный метод 'Parent' из' main() '. –

10

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

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

За сравнительно плохой пример :)

 
class RecordFile 
{ 
    public: 
     RecordFile(const std::string &filename); 

     void process(const Record &rec) 
     { 
      // Call the derived class function to filter out 
      // records the derived instance of this class does 
      // not care about 
      if (filterRecord(rec))  
      { 
       writeRecordToFile(rec);   
      } 
     }; 

    private: 
     // Returns true if the record is of importance 
     // and should be kept 
     virtual bool filterRecord(const Record &rec) = 0; 

     void writeRecordToFile(const Record &rec); 
}; 

+2

Я не понимаю, потому что частные методы не видны в производных классах. Как производный класс может переопределить метод, который он не может «увидеть» или вызвать или получить доступ каким-либо образом? – abelenky

+0

+1 - Вы дали практические аргументы в пользу аргумента Херба Саттера. –

+17

Abelenky, вы указали основной источник путаницы в отношении частных виртуальных машин, но факт в том, что вам не нужно * вызывать * функцию, чтобы иметь возможность * определить * ее. Это позволяет базовому классу рассказать своим потомкам: «Предоставьте мне функцию, но я один решаю, когда ее называть». –

9

ISO C++ 2003 явно не позволяет это сделать:

§10.3 состояний ничего о спецификатора доступа и содержит даже сноска во втором пункте с указанием в контексте виртуальной функции переопределяет:

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

Код полностью законный.

 Смежные вопросы

  • Нет связанных вопросов^_^