重写方法时关键字虚拟的作用是什么?我没有使用它,一切正常。
每个编译器在这方面的行为是否相同?
我应该使用它吗?
答案 0 :(得分:10)
没有它就无法覆盖成员函数。
你只能隐藏一个。
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
已使用过它。这是标准的保证,你可以信赖它。但是,有些人认为最好保持清晰。答案 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
,但仅限于文档目的。
答案 2 :(得分:6)
当一个函数是虚函数时,它在整个层次结构中保持虚拟,无论您是否每次都显式指定它。覆盖方法时,使用虚拟以便更明确 - 没有其他区别:)
class A
{
virtual void f()
{
/*...*/
};
};
class B:public A;
{
virtual void f() //same as just void f()
{
/*...*/
};
};
答案 3 :(得分:0)
扩展“轻量级比赛”的答案,也许这将有助于某些人了解它在做什么。
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXX');