Что означает виртуальное ключевое слово при переопределении метода?

Что делает ключевое слово 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

Другие вопросы по тегам