Что означает виртуальное ключевое слово при переопределении метода?
Что делает ключевое слово virtual при переопределении метода? Я им не пользуюсь и все отлично работает.
Каждый компилятор ведет себя одинаково в этом отношении?
Я должен использовать это или нет?
3 ответа
Вы не можете переопределить функцию-член без нее.
Вы можете скрыть только один.
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
уже использовал это. Это гарантируется стандартом, и вы можете положиться на него. Однако некоторые считают, что лучше сохранить это для ясности.
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
хотя, если только для целей документации.
Когда функция является виртуальной, она остается виртуальной во всей иерархии, независимо от того, указывается ли вы явно каждый раз, когда она является виртуальной. При переопределении метода, используйте виртуальный, чтобы быть более явным - никаких других отличий:)
class A
{
virtual void f()
{
/*...*/
};
};
class B:public A;
{
virtual void f() //same as just void f()
{
/*...*/
};
};
Расширяя ответ Light Races, возможно, это поможет некоторым людям увидеть, что он делает.
struct Base {
public:
void foo() {
printf_s("Base::foo\n");
}
};
struct Derived : Base {
void foo() {
printf_s("Derived::foo\n");
}
};
struct BaseVirtual {
public:
virtual void foo() {
printf_s("BaseVirtual::foo\n");
}
};
struct DerivedVirtual : BaseVirtual {
virtual void foo() {
printf_s("DerivedVirtual::foo\n");
}
};
Derived d;
d.foo(); // Outputs: Derived::foo
Base& b = d;
b.foo(); // Outputs: Base::foo
DerivedVirtual d2;
d2.foo(); // Outputs: DerivedVirtual::foo
BaseVirtual& b2 = d2;
b2.foo(); // Outputs: DerivedVirtual::foo