ВСЕ виртуальные функции должны быть реализованы в производных классах? - PullRequest
81 голосов
/ 19 января 2012

Это может показаться простым вопросом, но я нигде не могу найти ответ.

Предположим, у меня есть следующее:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

Это нормально, что класс Derived делаетне реализовать функцию bar ()?Что, если не ВСЕ мои производные классы нуждаются в функции bar (), но некоторые делают это.Все ли виртуальные функции абстрактного базового класса должны быть реализованы в производных классах или только те, которые являются чисто виртуальными?Спасибо

Ответы [ 5 ]

72 голосов
/ 19 января 2012

Производные классы не должны реализовывать все сами виртуальные функции. Им нужно только реализовать pure . 1 Это означает, что класс Derived в вопросе правильный. наследует реализацию bar от своего класса-предка Abstract. (Предполагается, что Abstract::bar реализован где-то. Код в вопросе объявляет метод, но не определяет его. Вы можете определить его в строке как ответ Тренки , или вы можете определить его отдельно. )


1 И даже тогда, только если производный класс будет создан . Если производный класс не создается напрямую, а существует только как базовый класс более производных классов, то именно этих классов отвечают за реализацию всех их чисто виртуальных методов. «Среднему» классу в иерархии разрешено оставлять нереализованными некоторые чисто виртуальные методы, как и базовый класс. Если «средний» класс реализует чисто виртуальный метод, то его потомки унаследуют эту реализацию, поэтому им не нужно будет повторно реализовывать его самостоятельно.

42 голосов
/ 19 января 2012

Только производные виртуальные методы должны быть реализованы в производных классах, но вам все еще нужно определение (а не просто объявление) других виртуальных методов.Если вы его не предоставите, компоновщик вполне может пожаловаться.

Итак, просто поставив {} после того, как ваш необязательный виртуальный метод даст вам пустую реализацию по умолчанию:

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

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

7 голосов
/ 19 января 2012

Стандарт ISO C ++ определяет, что все виртуальные методы класса, которые не являются чисто виртуальными, должны быть определены.

Проще говоря, правило:
Если ваш производный класс переопределяет виртуальный метод Базового класса, то он также должен предоставить определение. Если нет, то Базовый класс должен предоставить определение этого метода.

Согласно приведенному выше правилу в вашем примере кода, virtual void bar(); необходимо определение в базовом классе.

Ссылка:

C ++ 03 Standard:10.3 Виртуальные функции [class.virtual]

Виртуальная функция, объявленная в классе, должна быть определена или объявлена ​​как чистая (10.4) в этом классе, или в обоих;но никакой диагностики не требуется (3.2).

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

gcc faq также документирует его:

Стандарт ISO C ++ указывает, что все виртуальные методы класса, которые не являютсяДолжен быть определен чисто виртуальный, но не требуется никакой диагностики нарушений этого правила [class.virtual]/8.Исходя из этого предположения, GCC будет генерировать только неявно определенные конструкторы, оператор присваивания, деструктор и виртуальную таблицу класса в модуле перевода, который определяет его первый такой не встроенный метод.

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

Решение состоит в том, чтобы обеспечить определение всех не чистых виртуальных методов.Обратите внимание, что деструктор должен быть определен, даже если он объявлен чисто виртуальным [class.dtor]/7.

3 голосов
/ 19 января 2012

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

0 голосов
/ 19 января 2012

Да, верно, что производный класс должен ПЕРЕОБРАЗОВАТЬ функцию Pure Virtual в родительском классе.Родительский класс, имеющий Чистую Виртуальную Функцию, называется Абстрактным Классом только потому, что его дочерний класс должен давать свое собственное тело Чистой Виртуальной Функции.

Для Нормальных Виртуальных Функций: - Нет необходимости переопределять их далее, так как некоторыеДочерний класс может иметь эту функцию, а некоторые могут и не иметь.

Основное назначение механизма виртуальных функций - это полиморфизм времени выполнения, независимо от того, является ли основным назначением чистой виртуальной функции (абстрактного класса) обязательное присвоение имени функции с собственным телом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...