Если у меня есть базовый класс как так:
class Base {
public:
Base(){}
virtual void foo()=0;
};
Теперь, если я выведу какой-либо класс из базового класса, он должен будет переопределить foo()
,
Что делать, если я хотел поведение на foo()
для базового класса тоже? Так что у базового класса есть свой foo
и, кроме того, каждый из них должен переопределить foo
? Это возможно?
Если вы делаете что-то вроде:
class Base {
public:
Base(){}
virtual void foo() = 0;
};
void Base::foo() {
{
cout << "Hello";
}
вы получите абстрактный класс, так что вы будете не быть в состоянии создать объект b класса Base и заставить его использовать вашу реализацию foo (), вызвав b.foo ().
Так что это не то, что вы хотите! Следующий вопрос: почему вам разрешили предоставить реализацию для Base :: foo, если вы не можете ее использовать? Ну, на самом деле вы можете! Хотя не напрямую.
class Deriv : public Base {
public:
Deriv(){}
virtual void foo();
};
void Deriv::foo()
{
Base::foo(); cout << " world!";
}
Как вы можете видеть Base :: foo () Можно использоваться производными классами.
Вернемся к вашему вопросу. Ответ ты Можно делать именно то, что вы указали, за исключением того, что базовый класс будет абстрактным.
Альтернатива состоит в том, чтобы делать то, что делает большинство людей, и не указывать = 0, когда вы предоставляете реализацию для foo () в Base. Это означает, что производные классы Можно переопределить foo (), но не иметь к. На самом деле мне кажется, что это имеет смысл: в производных классах, для которых реализация по умолчанию Base :: foo () имеет смысл, вы сохраняете это, но для тех, кому нужно что-то другое, вы переопределяете это.
Обновление: я попытался придумать сценарий, который действительно требует того, о чем спрашивают вопросы, и придумал это:
Представьте, что Document и его производные классы представляют типы документов, и что Document содержит виртуальный метод getClassIcon (), возвращающий URL-адрес файла изображения для значка, представляющего тип документа. Для Document имеет смысл иметь значок (что-то, представляющее общий документ), а также имеет смысл требовать, чтобы все производные классы переопределяли getClassIcon () для предоставления своих собственных значков.
Сказав это, в этом конкретном примере, кажется, легко найти альтернативный дизайн: сделать Document :: getClassIcon () чисто виртуальным методом (= 0) (делая Document абстрактным классом) и добавить OtherDocument в качестве одного из его производных классов, давая Это была реализация getClassIcon Document ранее. PDFDocument, MSWordDocument и т. Д. Все будут необходимы для переопределения getClassIcon () по мере необходимости. То, что этот редизайн может быть использован, чтобы показать, что предыдущий дизайн (поддерживаемый воображаемой версией C ++, которая позволяет то, о чем спрашивает вопрос) связал роль базового класса, Document и роль стоящего класса для документов, которые не принадлежат ни к одному из известных типов, OtherDocument. Конечно, все это в глазах смотрящего 🙂 Можно утверждать, что второй дизайн был просто необходим из-за отсутствия функциональности в языке. Я думаю, что мы думаем (в значительной степени) в соответствии с (компьютерным) языком, на котором мы говорим. 🙂
Вы можете предоставить реализацию для чисто виртуального метода:
class Base {
...
virtual void foo()=0;
}
void Base::foo() {
... implementation goes here ...
}
Класс остается абстрактным. Если вы не хотите, чтобы он был абстрактным, вы должны удалить =0
, Однако, как только вы это сделаете, вы не сможете заставить производные классы предоставлять свои собственные реализации.
Другими словами, вы должны сделать выбор.