Что означает ключевое слово 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()
    {
        /*...*/
    };
};