Что означает ключевое слово virtual при переопределении метода?
Что делает ключевое слово virtual при переопределении метода? Я не использую его, и все работает нормально.
Поддерживает ли каждый компилятор одинаковый в этом отношении?
Должен ли я использовать его или нет?
Ответы
Ответ 1
Вы не можете переопределить функцию-член без нее.
Вы можете только скрыть его.
struct Base {
void foo() {}
};
struct Derived : Base {
void foo() {}
};
Derived::foo
не отменяет Base::foo
; он просто скрывает его, потому что он имеет то же имя, что и следующее:
Derived d;
d.foo();
вызывает Derived::foo
.
virtual
позволяет полиморфизм таким образом, чтобы вы фактически переопределяли функции:
struct Base {
virtual void foo() {}
};
struct Derived : Base {
virtual void foo() {} // * second `virtual` is optional, but clearest
};
Derived d;
Base& b = d;
b.foo();
Это вызывает Derived::foo
, потому что теперь это переопределяет Base::foo
— ваш объект является полиморфным.
(Вы также должны использовать для этого ссылки или указатели, из-за проблема среза.
-
Derived::foo
не нужно повторять ключевое слово virtual
, потому что Base::foo
уже использовал его. Это гарантируется стандартом, и вы можете положиться на него. Однако некоторые считают, что лучше всего сохранить это для ясности.
Ответ 2
Метод A virtual
в базовом классе будет каскадироваться через иерархию, делая каждый метод подкласса с той же сигнатурой также virtual
.
class Base{
public:
virtual void foo(){}
};
class Derived1 : public Base{
public:
virtual void foo(){} // fine, but 'virtual' is no needed
};
class Derived2 : public Base{
public:
void foo(){} // also fine, implicitly 'virtual'
};
Я бы рекомендовал писать virtual
, хотя, если только для целей документации.
Ответ 3
Когда функция виртуальна, она остается виртуальной по всей иерархии, независимо от того, явно ли вы указываете каждый раз, когда она виртуальна. При переопределении метода используйте виртуальный, чтобы быть более явным - никакой другой разницы:)
class A
{
virtual void f()
{
/*...*/
};
};
class B:public A;
{
virtual void f() //same as just void f()
{
/*...*/
};
};