Чистая virtual
функция должна быть реализована в производном типе, который будет непосредственно создан, однако базовый тип все еще может определять реализацию. Производный класс может явно вызывать реализацию базового класса (если это разрешено правами доступа), используя полностью ограниченное имя (вызывая A::f()
в вашем примере - если A::f()
было public
или protected
). Что-то вроде:
class B : public A {
virtual void f() {
// class B doesn't have anything special to do for f()
// so we'll call A's
// note that A's declaration of f() would have to be public
// or protected to avoid a compile time problem
A::f();
}
};
Вариант использования, который я могу придумать, - это когда более или менее разумное поведение по умолчанию, но разработчик класса хочет, чтобы такое поведение по умолчанию вызывалось только явно. Это также может быть случай, когда вы хотите, чтобы производные классы всегда выполняли свою собственную работу, но также могли вызывать общий набор функций.
Обратите внимание, что, хотя это разрешено языком, это не то, что я вижу обычно используемым (и тот факт, что это можно сделать, кажется, удивляет большинство программистов на C ++, даже опытных).
deported
. (либо в .inl, либо в .cpp для ссылки на обычные методы именования файлов).Чтобы было ясно, вы не понимаете, что = 0; после виртуальной функции значит.
= 0 означает, что производные классы должны обеспечивать реализацию, а не то, что базовый класс не может обеспечить реализацию.
На практике, когда вы помечаете виртуальную функцию как чистую (= 0), нет особого смысла в предоставлении определения, потому что оно никогда не будет вызываться, если кто-то явно не сделает этого через Base :: Function (...) или если Конструктор базового класса вызывает виртуальную функцию, о которой идет речь.
источник
Преимущество этого состоит в том, что он заставляет производные типы по-прежнему переопределять метод, но также обеспечивает реализацию по умолчанию или аддитивную реализацию.
источник
Если у вас есть код, который должен выполняться производным классом, но вы не хотите, чтобы он выполнялся напрямую - и вы хотите, чтобы он был переопределен.
Ваш код верен, хотя в целом это не часто используемая функция, и обычно ее можно увидеть только при попытке определить чистый виртуальный деструктор - в этом случае вы должны предоставить реализацию. Самое смешное, что как только вы вышли из этого класса, вам не нужно переопределять деструктор.
Следовательно, единственное разумное использование чисто виртуальных функций - это определение чистого виртуального деструктора в качестве ключевого слова «non-final».
Следующий код на удивление правильный:
источник
Например, вам придется отдать тело чисто виртуальному деструктору :)
Читайте: http://cplusplus.co.il/2009/08/22/pure-virtual-destructor/
(Ссылка не работает, используйте архив)
источник
Да, это правильно. В вашем примере классы, производные от A, наследуют как интерфейс f (), так и реализацию по умолчанию. Но вы заставляете производные классы реализовывать метод f () (даже если он только вызывает реализацию по умолчанию, предоставленную A).
Скотт Мейерс обсуждает это в Effective C ++ (2nd Edition) Item # 36. Различают наследование интерфейса и наследование реализации. Номер изделия мог измениться в последней редакции.
источник
Чистые виртуальные функции с телом или без него просто означают, что производные типы должны обеспечивать собственную реализацию.
Чистые тела виртуальных функций в базовом классе полезны, если ваши производные классы хотят вызвать реализацию вашего базового класса.
источник
Виртуальная пустота foo () = 0; синтаксис не означает, что вы не можете реализовать foo () в текущем классе, вы можете. Это также не означает, что вы должны реализовать его в производных классах . Прежде чем дать мне пощечину, давайте рассмотрим Алмазную проблему: (Неявный код, обратите внимание).
Теперь вызов obj-> foo () приведет к B :: foo (), а затем к C :: bar ().
Вы видите ... чистые виртуальные методы не должны быть реализованы в производных классах (foo () не имеет реализации в классе C - компилятор скомпилируется) В C ++ есть много лазеек.
Надеюсь, я мог помочь :-)
источник
C
в вашем примере. Вы можете создать экземпляр объекта типа,D
потому что он получает реализациюfoo
отB
.Один важный пример использования чисто виртуального метода с телом реализации - это когда вы хотите иметь абстрактный класс, но у вас нет подходящих методов в классе, чтобы сделать его чисто виртуальным. В этом случае вы можете сделать деструктор класса чисто виртуальным и поместить для этого желаемую реализацию (даже пустое тело). Например:
Этот метод делает
Foo
класс абстрактным и в результате невозможно создать экземпляр класса напрямую. В то же время вы не добавили дополнительный чисто виртуальный метод, чтобы сделатьFoo
класс абстрактным.источник