2011-06-18 3 views
11

Что делает ключевое слово virtual при переопределении метода? Я не использую его, и все работает нормально.Что означает виртуальное ключевое слово при переопределении метода?

Поддерживает ли каждый компилятор одинаковый в этом отношении?

Должен ли я использовать его или нет?

+0

возможно дубликат [C++ Virtual/Pure Virtual Разъяснения] (http://stackoverflow.com/questions/1306778/c-virtual-pure-virtual-explained) –

+0

@Harald: Нет. Разная тема. – Xeo

+0

Но я спрашиваю об использовании этого ключевого слова. Не об абстрактном виртуальном методе. – kravemir

ответ

11

Вы не можете переопределить функцию-член без него.

Вы можете только скрыть один.

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 — ваш объект является полиморфным.

(Вы также есть использовать ссылки или указатели на это, из-за the slicing problem.)


  • Derived::foo не нужно повторять virtual ключевое слово, потому что Base::foo уже использовал его. Это гарантируется стандартом, и вы можете положиться на него. Тем не менее, некоторые считают, что лучше всего сохранить это для ясности.
+2

Я знаю, что виртуальный необходим при объявлении метода, который можно переопределить. Я спросил об использовании этого ключевого слова при переопределении метода, а не объявлении. – kravemir

+1

@ Миро: Я не следую. Вы переопределяете функцию, объявляя другую, которая переопределяет ее. В любом случае, по крайней мере, мой последний параграф отвечает на ваш вопрос. –

8

Метод 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, хотя, если для документации цели только.

5

Когда функция виртуальна, она остается виртуальной по всей иерархии, независимо от того, указываете ли вы явным образом каждый раз, когда она виртуальна. При переопределении метода, использовать виртуальный для того, чтобы быть более явным - никакой другой разницы :)

class A 
{ 
    virtual void f() 
    { 
     /*...*/ 
    }; 
}; 

class B:public A; 
{ 
    virtual void f() //same as just void f() 
    { 
     /*...*/ 
    }; 
}; 
Смежные вопросы