Читая, что вы можете иметь финальные виртуальные функции в C++0x, я немного запутался. В чем разница, если просто исключить оба модификатора?
окончательные виртуальные функции в C++0x
Ответы (2)
Разница заключается в том, что его использует не база, а производная.
class Base {
virtual void foo() = 0;
};
class Derived : Base {
void foo() {}
// Still virtual because it's virtual in base- no way to "un-virtual" it
virtual void foo() final {}
// Now un-overridable.
};
Думайте об этом не как о предотвращении переопределений, а о предотвращении «большего» переопределения.
Когда я впервые столкнулся с использованием ключевого слова final
в сочетании с virtual
в C++, мне было интересно то же самое:
Если объявление метода
virtual
делает его наследуемым и переопределяемым, а объявление методаfinal
предотвращает переопределение этого метода, не Разве объявление метода оба не образуют противоречия?
Я думаю, что текущий принятый ответ на этот вопрос хорош, но я хотел немного развить его, основываясь на том, что я нашел, глядя на это.
Рассмотрим следующий класс:
class A {
public:
void hide_me();
virtual void override_me();
virtual void cant_override_me() final;
};
Важно понимать, что все три объявления метода различны и означают разные вещи.
Первое:
void hide_me();
не является виртуальным и поэтому по определению не может быть переопределен.
Третий:
virtual void cant_override_me() final;
объявлен как final
и поэтому не может быть переопределен, в том числе по определению.
Разница в том, что поскольку hide_me
не является виртуальным, его переопределение неприменимо, в то время как cant_override_me
можно считать подходящим для переопределения (потому что это virtual
,) но он также имеет переопределение disabled из-за модификатора final
. Другими словами, переопределение не применяется к методам, которые не объявлены virtual
, но применимо к методам virtual
, вы просто не можете переопределить их, если они также объявлены final
.
Теперь рассмотрим дочерний класс:
class B: public A {
public:
void hide_me(); // this hide's A's definition of "hide_me()"; this is not overriding.
void override_me(); // implicit "virtual"
//void cant_override_me(); // implicit "virtual"; compilation fails
};
Вы можете переопределить hide_me()
для класса B
, но это просто перегрузка или скрытие, отсюда и название функции. B
по-прежнему может получить доступ к методу hide_me
A
через A::hide_me()
, но кто-то еще, у кого есть ссылка на B
, объявленная как B
, т.е.:
B *my_b = new B();
должен получить доступ к скрытому теперь A
определению hide_me
через my_b->A::hide_me()
.
Вы не можете предоставить переопределение cant_override_me()
в B
.
В качестве полного примера, вот небольшое переопределение программы, чтобы проиллюстрировать, что происходит:
#include <cstdio>
class A {
public:
inline void hide_me() {
printf("a hide_me\n");
}
virtual void override_me();
virtual void cant_override_me() final;
};
class B: public A {
public:
inline void hide_me() {
printf("b hide_me\n");
}
void override_me();
inline void foo() {
A::hide_me();
}
// can't override cant_override_me
};
void A::override_me() {
printf("a override_me\n");
}
void A::cant_override_me() {
printf("a cant_override_me\n");
}
void B::override_me() {
printf("b override_me\n");
}
int main (int argc, char *argv[]) {
A *a = new A();
A *ab = new B();
B *b = new B();
a->hide_me();
ab->hide_me();
b->hide_me();
b->A::hide_me();
printf("---\n");
a->override_me();
ab->override_me();
b->override_me();
b->A::override_me();
}
Программа выводит
a hide_me
a hide_me
b hide_me
a hide_me
---
a override_me
b override_me
b override_me
a override_me
Base
унаследован от другого класса, который объявляет исходный базовый методf
. - person Damien_The_Unbeliever   schedule 22.07.2011