据我了解,override
关键字声明给定声明实现了基本virtual
方法,如果找不到匹配的基本方法,则编译应该失败。
我对final
关键字的理解是它告诉编译器没有类会覆盖这个virtual
函数。
override final
是多余的? It seems to compile fine。 override final
传达的final
没有哪些信息?这种组合的用例是什么?
答案 0 :(得分:38)
final
不需要该函数首先覆盖任何内容。其效果在[class.virtual] / 4中定义为
如果某个班级
f
中的虚拟函数B
标有。{ virt-specifierfinal
以及来自D
函数B
的类D::f
覆盖B::f
,该程序格式不正确。
那就是它。现在override final
只是意味着
“此函数会覆盖基类1(override
),并且不能自行覆盖(final
)。”
final
自己会强加一个较弱的要求。
override
和final
有独立行为。
请注意,final
只能用于虚拟功能 - [class.mem] / 8
virt-specifier-seq 只出现在a的声明中 虚拟成员函数(10.3)。
因此声明
void foo() final;
实际上与
相同virtual void foo() final override;
由于两者都要求foo
覆盖某些内容 - 第二个声明使用override
,第一个声明是有效的,当且仅当foo
隐式虚拟时,即当foo
覆盖基类中名为foo
的虚函数时,会使派生的foo
自动虚拟。因此override
将是多余的发生final
而非virtual
的声明
尽管如此,后一种声明表达的意图更加清晰,绝对应该是首选。
答案 1 :(得分:16)
final
并不一定意味着该函数被覆盖。在继承层次结构中的第一个声明中将虚拟函数声明为final
是完全有效的(如果有些可疑的话)。
我可以想到创建一个虚拟且立即最终的函数的一个原因是,如果你想阻止派生类给出相同的名称&参数具有不同的含义。
答案 2 :(得分:4)
(如果你赶时间的话,请跳到最后看看结论。)
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
是独立的。
override
表示该函数覆盖其基类中的虚函数。请参阅f1()
和f3()
。final
表示该函数不能被其派生类重写。 (但函数本身不需要覆盖基类虚函数。)请参阅f6()
和f4()
。比较f2()
和f3()
。我们知道,如果声明成员函数没有virtual
和final
,则意味着它已经覆盖了基类中的虚函数。在这种情况下,关键字override
是多余的。
比较f4()
和f5()
。我们知道,如果使用virtual
声明成员函数,并且如果它不是继承层次结构中的第一个虚函数,那么我们应该使用override
来指定覆盖关系。否则,我们可能会意外地在派生类中添加新的虚函数。
比较f1()
和f7()
。我们知道任何成员函数,而不仅仅是虚函数,都可以在派生类中重写。 virtual
指定的是多态,这意味着决定运行哪个函数会延迟到运行时而不是编译时。 (在实践中应该避免这种情况。)
比较f7()
和f8()
。我们知道我们甚至可以覆盖基类函数并使其成为新的虚函数。 (这意味着从f8()
派生的类的任何成员函数D
都是虚拟的。)(在实践中也应该避免这种情况。)
比较f7()
和f9()
。我们知道,当我们想要覆盖派生类中的虚函数而忘记在基类中添加关键字override
时,virtual
可以帮助我们找到错误。
总之,我自己观点中的最佳做法是:
virtual
; override
指定派生类中的覆盖虚函数,除非还指定了final
。答案 3 :(得分:1)
否final
并不一定意味着override
。实际上,您可以声明virtual
函数,并立即声明final
see here。 final
关键字只是声明没有派生的class
可以创建此函数的覆盖。
override
关键字非常重要,因为它强制确实实际上覆盖了虚函数(而不是声明一个新的无关函数)。见this post regarding override
长话短说,它们各自都有自己的特定目的,使用它们通常都是正确的。
答案 4 :(得分:1)
以下代码(使用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
没有指定基类覆盖部分。