В производном классе сигнатура функции такая:
virtual void foo(); //Derived::foo
, в котором не упоминается const
. Это неконстантная функция-член, в то время как Base::foo
является const функцией-членом. Это две разные функции, потому что const
является частью сигнатуры функции.
virtual void foo() const; //Base::foo
Производный класс НЕ переопределяет эту функцию, вместо этого он добавляет другую функцию.
Итак, исправление таково:
class Derived : public Base {
public:
virtual void foo() const {
cout << "Derived::foo()" << endl;
}
};
Поскольку const
является частью сигнатуры функции. Поэтому вы должны упомянуть об этом, когда намереваетесь переопределить foo базы.
@ Дэвка спросил:
так почему версия const выбрана вместо non-const? Есть ли какое-то правило или это просто первый вариант?
Это потому, что static тип obj
равен Base
, а имя функции определяется на основе статического типа объекта. Base
даже не имеет неконстантной версии. Таким образом, нет сомнений в том, что он был выбран или отклонен. Его не существует в Base
для начала.
void func(Base& obj) {
obj.foo(); //calls Base::foo
}
Однако, если вы измените приведенный выше код на следующий:
void func(Derived & obj) {
obj.foo(); //calls Derived:foo
}
Теперь будет выбрана неконстантная версия, потому что Base::foo
скрыт в Derived
классе.
Поскольку Derived::foo
скрывает Base::foo
, поэтому вы не можете вызвать последний, используя экземпляр Derived
.
Теперь давайте раскроем Base::foo
и проведем еще несколько экспериментов.
class Derived : public Base {
public:
using Base::foo; //<----------------this unhides Base::foo
virtual void foo() {
cout << "Derived::foo()" << endl;
}
};
Теперь в Derived обе функции (как константной, так и неконстантной версии) доступны, невидимые. Теперь несколько интересных вопросов.
Поскольку теперь в Derived обе функции не скрыты, какая функция будет вызываться в каждой функции ниже?
void f(Derived& obj) {
obj.foo(); //Which function? Base::foo or Derived::foo?
}
void g(const Derived & obj) {
obj.foo(); //Which function? Base::foo or Derived::foo?
}
Первый вызовет Derived::foo
, который является неконстантной версией, а второй вызовет Base::foo
, который является константной версией. Причина проста: с const-объектом можно вызывать только функции * * const , но с неконстантными объектами можно вызывать обе функции, однако выбирается неконстантная версия, если она доступна .
Смотрите онлайн демо: http://www.ideone.com/955aY