C++"virtual"关键字,用于派生类中的函数.有必要吗?

Ana*_*rki 211 c++ overriding virtual-functions

使用下面给出的结构定义......

struct A {
    virtual void hello() = 0;
};
Run Code Online (Sandbox Code Playgroud)

方法#1:

struct B : public A {
    virtual void hello() { ... }
};
Run Code Online (Sandbox Code Playgroud)

方法#2:

struct B : public A {
    void hello() { ... }
};
Run Code Online (Sandbox Code Playgroud)

这两种覆盖hello函数的方法有什么区别吗?

Jam*_*lis 172

它们完全一样.除了第一种方法需要更多打字并且可能更清晰之外,它们之间没有区别.

  • 这是事实,但[Mozilla C++可移植性指南](https://developer.mozilla.org/en/C___Portability_Guide#Use_virtual_declaration_on_all_subclass_virtual_member_functions)建议始终使用虚拟,因为"某些编译器"会发出警告,如果不这样做.太糟糕了,他们没有提到任何这种编译器的例子. (22认同)
  • @SergeyTachenov根据**clifford**对[他自己的答案]的评论(http://stackoverflow.com/a/4895389/673852),这类编译器的例子是armcc. (5认同)
  • 我还要补充一点,明确地将其标记为虚拟将有助于提醒您将析构函数设置为虚拟. (4认同)
  • @Rasmi,[新的可移植性指南在这里](https://developer.mozilla.org/en-US/docs/Mozilla/C++_Portability_Guide#Use_override_on_subclass_virtual_member_functions),但现在它建议使用`override`关键字. (4认同)

Cli*_*ord 81

函数的"虚拟性"是隐式传播的,但是如果virtual关键字没有显式使用,我使用的至少一个编译器会生成警告,所以如果只是为了保持编译器安静,你可能想要使用它.

从纯粹的风格角度来看,包括virtual关键字清楚地向用户宣传该功能是虚拟的.这对于任何进一步细分B而不必检查A的定义的人来说都很重要.对于深层次的层次结构,这变得尤为重要.

  • @James:armcc(ARM的ARM设备编译器) (32认同)
  • 这是哪个编译器? (11认同)

R S*_*ahu 50

virtual派生类中不需要该关键字.以下是C++草案标准(N3337)(强调我的)的支持文档:

10.3虚函数

2如果vf在类Base和类中声明了虚方法成员函数,该类Derived直接或间接地从具有相同名称Base的成员函数派生vf,参数类型列表(8.3.5),cv-qualification和ref-qualifier(或者没有相同的),Base::vf如果声明,那么Derived::vf也是虚拟的(无论是否如此声明)并覆盖Base::vf.

  • 这是迄今为止最好的答案. (3认同)

Col*_*ett 31

不,不需要virtual派生类的虚函数覆盖上的关键字.但值得一提的是一个相关的陷阱:未能覆盖虚函数.

重写失败,如果你打算重写在派生类中的虚函数,但做出一个错误的签名,以便它声明了一个新的和不同的虚函数发生.此函数可能是基类函数的重载,或者名称可能不同.无论您是否virtual在派生类函数声明中使用关键字,编译器都无法告诉您打算从基类重写函数.

然而,幸运的是,C++ 11 显式覆盖语言特性解决了这个缺陷,该特性允许源代码清楚地指定成员函数旨在覆盖基类函数:

struct Base {
    virtual void some_func(float);
};

struct Derived : Base {
    virtual void some_func(int) override; // ill-formed - doesn't override a base class method
};
Run Code Online (Sandbox Code Playgroud)

编译器将发出编译时错误,并且编程错误将立即显而易见(可能Derived中的函数应该将a float作为参数).

参见WP:C++ 11.


Suj*_*osh 11

添加"虚拟"关键字是一种很好的做法,因为它提高了可读性,但并不是必需的.在基类中声明为虚拟的函数,并且在派生类中具有相同的签名,默认情况下被视为"虚拟".


har*_*per 7

当您virtual在派生类中编写或省略它时,编译器没有区别.

但是你需要查看基类来获取这些信息.因此virtual,如果您想向人类展示此功能是虚拟的,我建议在派生类中添加关键字.