据我所知,override关键字声明给定的声明实现了一个基 virtual方法,如果没有找到匹配的基方法,编译就会失败。
override
virtual
我对 final关键字的理解是,它告诉编译器没有类可以覆盖这个 virtual函数。
final
那么 override final是多余的吗?看起来编译得很好.哪些信息是 override final传达的,而 final没有?这种组合的用例是什么?
override final
final并不一定意味着函数被重写。在继承层次结构中的 第一声明中,将虚函数声明为 final是完全有效的(如果值有些可疑的话)。
我能想到的创建一个虚拟的、立即的最终函数的一个原因是,如果你想给 预防一个派生类赋予相同的名称和参数一个不同的含义。
没有 final并不一定意味着 override。实际上,您可以声明一个立即声明 final 看这里的 virtual函数。final关键字只是说明没有派生的 class可以创建此函数的重写。
class
override关键字很重要,因为它强制您实际上正在重写一个虚函数(而不是声明一个新的不相关函数)。见 关于 override的这篇文章
所以长话短说,它们各自服务于自己的特定目的,通常正确的做法是同时使用两者。
final首先不要求函数覆盖任何内容
如果某个类 B中的虚函数 f用 Virt 指定符 final,在从 B派生的类 D中,函数 D::f 重写 B::f时,程序格式不正确。
B
f
D
D::f
B::f
就是这样,现在 override final意味着 “此函数重写基类1(override) ,不能重写本身(final)。” 单独的 final会强加一个较弱的要求。 override和 final有独立的行为。
注意,final只能用于虚函数-[ class.mem ]/8
Virt-specfier-seq只应出现在 虚拟成员函数(10.3)。
所以我才发表声明
void foo() final;
实际上等同于
virtual void foo() final override;
由于两者都要求 foo覆盖某些内容——第二个声明使用 override,第一个声明使用当且仅当 foo是隐式虚拟的时候才有效,也就是说 当 foo在基类中重写名为 foo的虚函数时,将使派生类中的 foo自动成为虚函数。。因此,在发生 final而不是 virtual的声明中,override是多余的。 尽管如此,后一项声明表达的意图要清楚得多,而且肯定应该更为可取。
foo
编译以下代码(使用 final说明符)。但是当 final被 override final替换时,编译失败。因此,override final比 final传递更多的信息(并防止编译)。
class Base { public: virtual ~Base() {} }; class Derived : public Base { public: virtual void foo() final { std::cout << "in Derived foo\n"; } };
本质上,override final说这个方法不能在任何派生类 还有中重写,这个方法重写基类中的虚方法。单独的 final不指定基类重写部分。
(如果你赶时间,可以跳到最后看结论。)
override和 final只能在虚函数的声明中出现。而且这两个关键字都可以在同一个函数声明中使用,但是使用它们是否有用取决于具体情况。
以下面的代码为例:
#include <iostream> using std::cout; using std::endl; struct B { virtual void f1() { cout << "B::f1() "; } virtual void f2() { cout << "B::f2() "; } virtual void f3() { cout << "B::f3() "; } virtual void f6() final { cout << "B::f6() "; } void f7() { cout << "B::f7() "; } void f8() { cout << "B::f8() "; } void f9() { cout << "B::f9() "; } }; struct D : B { void f1() override { cout << "D::f1() "; } void f2() final { cout << "D::f2() "; } void f3() override final { cout << "D::f3() "; } // need not have override // should have override, otherwise add new virtual function virtual void f4() final { cout << "D::f4() "; } //virtual void f5() override final; // Error, no virtual function in base class //void f6(); // Error, override a final virtual function void f7() { cout << "D::f7() "; } virtual void f8() { cout << "D::f8() "; } //void f9() override; // Error, override a nonvirtual function }; int main() { B b; D d; B *bp = &b, *bd = &d; D *dp = &d; bp->f1(); bp->f2(); bp->f3(); bp->f6(); bp->f7(); bp->f8(); bp->f9(); cout << endl; bd->f1(); bd->f2(); bd->f3(); bd->f6(); bd->f7(); bd->f8(); bd->f9(); cout << endl; dp->f1(); dp->f2(); dp->f3(); dp->f6(); dp->f7(); dp->f8(); dp->f9(); cout << endl; return 0; }
输出是
B::f1() B::f2() B::f3() B::f6() B::f7() B::f8() B::f9() D::f1() D::f2() D::f3() B::f6() B::f7() B::f8() B::f9() D::f1() D::f2() D::f3() B::f6() D::f7() D::f8() B::f9()
比较 f1()和 f6(),我们知道 override和 final在语义上是独立的。
f1()
f6()
f3()
f4()
比较 f2()和 f3()。我们知道,如果一个成员函数在没有 virtual和 final的情况下声明,这意味着它已经覆盖了基类中的一个虚函数。在这种情况下,关键词 override是多余的。
f2()
比较 f4()和 f5()。我们知道,如果一个成员函数是用 virtual声明的,如果它不是继承层次结构中的 第一虚函数,那么我们应该使用 override来指定覆盖关系。否则,我们可能会意外地在派生类中添加新的虚函数。
f5()
比较 f1()和 f7()。我们知道任何成员函数,不仅仅是虚函数,都可以在派生类中被重写。virtual指定的是 多态性,这意味着关于运行哪个函数的决定被延迟到运行时而不是编译时。(在实践中应避免这种情况。)
f7()
比较 f7()和 f8()。我们知道,我们甚至可以重写一个基类函数,使其成为一个新的虚函数。(这意味着从 D派生的类的任何成员函数 f8()都是虚的。)(在实践中也应避免这种情况。)
f8()
比较 f7()和 f9()。我们知道,当我们想在派生类中重写虚函数而忘记在基类中添加关键字 virtual时,override可以帮助我们找到错误。
f9()
总而言之,我个人认为最好的做法是: