final 是否意味着覆盖?
Does final imply override?
据我了解,override
关键字表示给定的声明实现了基 virtual
方法,如果找不到匹配的基方法,编译应该会失败。
我对 final
关键字的理解是它告诉编译器任何 class 都不应覆盖此 virtual
函数。
所以override final
是多余的吗? It seems to compile fine。 override final
传达了哪些 final
没有传达的信息?这种组合的用例是什么?
final
并不一定意味着函数被覆盖。在继承层次结构中的 first 声明中将虚函数声明为 final
是完全有效的(如果值有点可疑)。
我能想到创建一个虚拟且立即结束的函数的一个原因是,如果您想防止派生的class给出相同的名称和参数不同的意思。
没有final
并不一定意味着override
。事实上,您可以声明一个 virtual
函数,然后立即声明 final
see here。 final
关键字简单地声明没有派生的 class
可以创建此函数的覆盖。
override
关键字很重要,因为它强制您确实实际上覆盖了一个虚函数(而不是声明一个新的不相关的函数)。参见 this post regarding override
长话短说,它们各自服务于自己的特定目的,通常两者都使用是正确的。
final
一开始不需要函数覆盖任何东西。它的效果在[class.virtual]/4中定义为
If a virtual function f
in some class B
is marked with the
virt-specifier final
and in a class D
derived from B
a function D::f
overrides B::f
, the program is ill-formed.
就是这样。现在 override final
就意味着
„此函数覆盖基数 class 一个 (override
) 并且不能自行覆盖 (final
)。“
final
本身会施加较弱的要求。
override
和 final
具有独立的行为。
请注意 final
只能用于虚函数 - [class.mem]/8
A virt-specifier-seq shall appear only in the declaration of a
virtual member function (10.3).
因此声明
void foo() final;
实际上与
相同
virtual void foo() final override;
因为两者都需要 foo
来覆盖某些东西 - 第二个声明使用 override
,第一个声明有效当且仅当 foo
是隐式虚拟的,即 当 foo
覆盖基 class 中名为 foo
的虚函数时,这使得派生函数中的 foo
自动成为虚函数。 因此override
在出现 final
而不是 virtual
的声明中是多余的。
尽管如此,后一种声明表达的意图更加清晰,绝对应该是首选。
以下代码(带有 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
表示此方法不能在任何派生 class 和 中重写此方法重写基 class 中的虚拟方法]. final
单独没有指定基础 class 覆盖部分。
(赶时间的可以跳到最后看结论)
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
表示该函数正在覆盖其基础 class 中的虚函数。参见 f1()
和 f3()
。
final
表示该函数不能被派生的 class 覆盖。 (但函数本身不需要重写基础 class 虚函数。)参见 f6()
和 f4()
.
比较f2()
和f3()
。我们知道,如果一个成员函数声明时不带virtual
而带final
,就意味着它已经覆盖了基class中的一个虚函数。在这种情况下,关键字 override
是多余的。
比较f4()
和f5()
。我们知道,如果一个成员函数是用virtual
声明的,如果它不是继承层次中第第一个虚函数,那么我们应该用override
来指定覆盖关系。否则,我们可能会不小心在 derived class.
中添加新的虚函数
比较f1()
和f7()
。我们知道,任何成员函数,不仅仅是虚函数,都可以在派生class中被覆盖。 virtual
指定的是 多态性 ,这意味着 运行 哪个函数的决定延迟到 运行 时间而不是编译时间。 (这在实践中应该避免。)
比较f7()
和f8()
。我们知道我们甚至可以重写一个基础 class 函数并使它成为一个新的虚拟函数。 (这意味着从 D
派生的 class 的任何成员函数 f8()
都是虚函数。)(这在实践中也应该避免。)
比较f7()
和f9()
。我们知道 override
可以帮助我们在 derived class 中重写虚函数而忘记在 base class 中添加关键字 virtual
时找到错误。
总结,我个人认为的最佳实践是:
- 仅 在基class;[=87 中的第一个 虚函数声明中使用
virtual
=]
- 总是使用
override
在派生 class 中指定覆盖虚函数,除非还指定了 final
。
据我了解,override
关键字表示给定的声明实现了基 virtual
方法,如果找不到匹配的基方法,编译应该会失败。
我对 final
关键字的理解是它告诉编译器任何 class 都不应覆盖此 virtual
函数。
所以override final
是多余的吗? It seems to compile fine。 override final
传达了哪些 final
没有传达的信息?这种组合的用例是什么?
final
并不一定意味着函数被覆盖。在继承层次结构中的 first 声明中将虚函数声明为 final
是完全有效的(如果值有点可疑)。
我能想到创建一个虚拟且立即结束的函数的一个原因是,如果您想防止派生的class给出相同的名称和参数不同的意思。
没有final
并不一定意味着override
。事实上,您可以声明一个 virtual
函数,然后立即声明 final
see here。 final
关键字简单地声明没有派生的 class
可以创建此函数的覆盖。
override
关键字很重要,因为它强制您确实实际上覆盖了一个虚函数(而不是声明一个新的不相关的函数)。参见 this post regarding override
长话短说,它们各自服务于自己的特定目的,通常两者都使用是正确的。
final
一开始不需要函数覆盖任何东西。它的效果在[class.virtual]/4中定义为
If a virtual function
f
in some classB
is marked with the virt-specifierfinal
and in a classD
derived fromB
a functionD::f
overridesB::f
, the program is ill-formed.
就是这样。现在 override final
就意味着
„此函数覆盖基数 class 一个 (override
) 并且不能自行覆盖 (final
)。“
final
本身会施加较弱的要求。
override
和 final
具有独立的行为。
请注意 final
只能用于虚函数 - [class.mem]/8
A virt-specifier-seq shall appear only in the declaration of a virtual member function (10.3).
因此声明
void foo() final;
实际上与
相同virtual void foo() final override;
因为两者都需要 foo
来覆盖某些东西 - 第二个声明使用 override
,第一个声明有效当且仅当 foo
是隐式虚拟的,即 当 foo
覆盖基 class 中名为 foo
的虚函数时,这使得派生函数中的 foo
自动成为虚函数。 因此override
在出现 final
而不是 virtual
的声明中是多余的。
尽管如此,后一种声明表达的意图更加清晰,绝对应该是首选。
以下代码(带有 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
表示此方法不能在任何派生 class 和 中重写此方法重写基 class 中的虚拟方法]. final
单独没有指定基础 class 覆盖部分。
(赶时间的可以跳到最后看结论)
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
表示该函数正在覆盖其基础 class 中的虚函数。参见f1()
和f3()
。final
表示该函数不能被派生的 class 覆盖。 (但函数本身不需要重写基础 class 虚函数。)参见f6()
和f4()
.
比较
f2()
和f3()
。我们知道,如果一个成员函数声明时不带virtual
而带final
,就意味着它已经覆盖了基class中的一个虚函数。在这种情况下,关键字override
是多余的。比较
f4()
和f5()
。我们知道,如果一个成员函数是用virtual
声明的,如果它不是继承层次中第第一个虚函数,那么我们应该用override
来指定覆盖关系。否则,我们可能会不小心在 derived class. 中添加新的虚函数
比较
f1()
和f7()
。我们知道,任何成员函数,不仅仅是虚函数,都可以在派生class中被覆盖。virtual
指定的是 多态性 ,这意味着 运行 哪个函数的决定延迟到 运行 时间而不是编译时间。 (这在实践中应该避免。)比较
f7()
和f8()
。我们知道我们甚至可以重写一个基础 class 函数并使它成为一个新的虚拟函数。 (这意味着从D
派生的 class 的任何成员函数f8()
都是虚函数。)(这在实践中也应该避免。)比较
f7()
和f9()
。我们知道override
可以帮助我们在 derived class 中重写虚函数而忘记在 base class 中添加关键字virtual
时找到错误。
总结,我个人认为的最佳实践是:
- 仅 在基class;[=87 中的第一个 虚函数声明中使用
virtual
=] - 总是使用
override
在派生 class 中指定覆盖虚函数,除非还指定了final
。