C++11 中函数的“final”关键字的目的是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8824587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the purpose of the "final" keyword in C++11 for functions?
提问by lezebulon
What is the purpose of the final
keyword in C++11 for functions? I understand it prevents function overriding by derived classes, but if this is the case, then isn't it enough to declare as non-virtual your final
functions? Is there another thing I'm missing here?
final
C++11 中函数关键字的用途是什么?我知道它可以防止派生类覆盖函数,但如果是这种情况,那么将final
函数声明为非虚拟函数还不够吗?还有什么我在这里想念的吗?
采纳答案by David Rodríguez - dribeas
What you are missing, as idljarn already mentioned in a comment is that if you are overridinga function from a base class, then you cannot possibly mark it as non-virtual:
您缺少什么,正如 idljarn 在评论中已经提到的那样,如果您从基类覆盖一个函数,那么您不可能将其标记为非虚拟:
struct base {
virtual void f();
};
struct derived : base {
void f() final; // virtual as it overrides base::f
};
struct mostderived : derived {
//void f(); // error: cannot override!
};
回答by Nawaz
It is to prevent a class from being inherited. From Wikipedia:
C++11 also adds the ability to prevent inheriting from classes or simply preventing overriding methods in derived classes. This is done with the special identifier final. For example:
struct Base1 final { }; struct Derived1 : Base1 { }; // ill-formed because the class Base1 // has been marked final
It is also used to mark a virtual function so as to prevent it from being overridden in the derived classes:
struct Base2 { virtual void f() final; }; struct Derived2 : Base2 { void f(); // ill-formed because the virtual function Base2::f has // been marked final };
这是为了防止类被继承。来自维基百科:
C++11 还增加了防止从类继承或简单地防止在派生类中覆盖方法的能力。这是通过特殊标识符 final 完成的。例如:
struct Base1 final { }; struct Derived1 : Base1 { }; // ill-formed because the class Base1 // has been marked final
它还用于标记虚函数,以防止它在派生类中被覆盖:
struct Base2 { virtual void f() final; }; struct Derived2 : Base2 { void f(); // ill-formed because the virtual function Base2::f has // been marked final };
Wikipedia further makes an interesting point:
维基百科进一步提出了一个有趣的观点:
Note that neither
override
norfinal
are language keywords. They are technically identifiers; they only gain special meaning when used in those specific contexts. In any other location, they can be valid identifiers.
请注意,语言关键字既不是
override
也不final
是。它们在技术上是标识符;它们只有在那些特定的上下文中使用时才会获得特殊的含义。在任何其他位置,它们可以是有效的标识符。
That means, the following is allowed:
这意味着,允许以下内容:
int const final = 0; // ok
int const override = 1; // ok
回答by chris green
"final" also allows a compiler optimization to bypass the indirect call:
“final”还允许编译器优化绕过间接调用:
class IAbstract
{
public:
virtual void DoSomething() = 0;
};
class CDerived : public IAbstract
{
void DoSomething() final { m_x = 1 ; }
void Blah( void ) { DoSomething(); }
};
with "final", the compiler can call CDerived::DoSomething()
directly from within Blah()
, or even inline. Without it, it has to generate an indirect call inside of Blah()
because Blah()
could be called inside a derived class which has overridden DoSomething()
.
使用“final”,编译器可以CDerived::DoSomething()
直接从内调用Blah()
,甚至内联调用。没有它,它必须在内部生成一个间接调用,Blah()
因为Blah()
可以在已覆盖的派生类内部调用DoSomething()
。
回答by Mario Knezovi?
Nothing to add to the semantic aspects of "final".
没有什么可以添加到“final”的语义方面。
But I'd like to add to chris green's comment that "final" might become a very important compiler optimization techniquein the not so distant future. Not only in the simple case he mentioned, but also for more complex real-world class hierarchies which can be "closed" by "final", thus allowing compilers to generate more efficient dispatching code than with the usual vtable approach.
但我想补充一下 chris green 的评论,即在不久的将来,“final”可能会成为一种非常重要的编译器优化技术。不仅在他提到的简单情况下,而且对于可以通过“final”“关闭”的更复杂的现实世界类层次结构,从而允许编译器生成比通常的 vtable 方法更有效的调度代码。
One key disadvantage of vtables is that for any such virtual object (assuming 64-bits on a typical Intel CPU) the pointer alone eats up 25% (8 of 64 bytes) of a cache line. In the kind of applications I enjoy to write, this hurts very badly. (And from my experience it is the #1 argument against C++ from a purist performance point of view, i.e. by C programmers.)
vtables 的一个主要缺点是,对于任何此类虚拟对象(假设在典型的 Intel CPU 上为 64 位),仅指针就占用了 25%(64 字节中的 8 个)缓存行。在我喜欢写的那种应用程序中,这很伤人。(根据我的经验,从纯粹的性能角度来看,即 C 程序员,这是反对 C++ 的#1 论点。)
In applications which require extreme performance, which is not so unusual for C++, this might indeed become awesome, not requiring to workaround this problem manually in C style or weird Template juggling.
在需要极端性能的应用程序中,这对于 C++ 来说并不罕见,这可能确实变得很棒,不需要在 C 风格或奇怪的模板杂耍中手动解决这个问题。
This technique is known as Devirtualization. A term worth remembering. :-)
这种技术被称为去虚拟化。一个值得记住的词。:-)
There is a great recent speech by Andrei Alexandrescu which pretty well explains how you can workaround such situations today and how "final" might be part of solving similar cases "automatically" in the future (discussed with listeners):
Andrei Alexandrescu 最近发表了一篇很棒的演讲,它很好地解释了您今天如何解决此类情况,以及“最终”如何成为未来“自动”解决类似案例的一部分(与听众讨论):
http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly
http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly
回答by YoungJohn
A use-case for the 'final' keyword that I am fond of is as follows:
我喜欢的“final”关键字的用例如下:
// This pure abstract interface creates a way
// for unit test suites to stub-out Foo objects
class FooInterface
{
public:
virtual void DoSomething() = 0;
private:
virtual void DoSomethingImpl() = 0;
};
// Implement Non-Virtual Interface Pattern in FooBase using final
// (Alternatively implement the Template Pattern in FooBase using final)
class FooBase : public FooInterface
{
public:
virtual void DoSomething() final { DoFirst(); DoSomethingImpl(); DoLast(); }
private:
virtual void DoSomethingImpl() { /* left for derived classes to customize */ }
void DoFirst(); // no derived customization allowed here
void DoLast(); // no derived customization allowed here either
};
// Feel secure knowing that unit test suites can stub you out at the FooInterface level
// if necessary
// Feel doubly secure knowing that your children cannot violate your Template Pattern
// When DoSomething is called from a FooBase * you know without a doubt that
// DoFirst will execute before DoSomethingImpl, and DoLast will execute after.
class FooDerived : public FooBase
{
private:
virtual void DoSomethingImpl() {/* customize DoSomething at this location */}
};
回答by Aaron McDaid
Final cannot be applied to non-virtual functions.
Final 不能应用于非虚函数。
error: only virtual member functions can be marked 'final'
It wouldn't be very meaningful to be able to mark a non-virtual method as 'final'. Given
能够将非虚拟方法标记为“最终”并没有多大意义。给定的
struct A { void foo(); };
struct B : public A { void foo(); };
A * a = new B;
a -> foo(); // this will call A :: foo anyway, regardless of whether there is a B::foo
a->foo()
will always call A::foo
.
a->foo()
会一直打电话A::foo
。
But, if A::foo was virtual
, then B::foo would override it. This might be undesirable, and hence it would make sense to make the virtual function final.
但是,如果 A::foo 是virtual
,那么 B::foo 将覆盖它。这可能是不可取的,因此将虚函数设为 final 是有意义的。
The question is though, whyallow final on virtual functions. If you have a deep hierarchy:
问题是,为什么在虚函数上允许 final 。如果您有很深的层次结构:
struct A { virtual void foo(); };
struct B : public A { virtual void foo(); };
struct C : public B { virtual void foo() final; };
struct D : public C { /* cannot override foo */ };
Then the final
puts a 'floor' on how much overriding can be done. Other classes can extend A and B and override their foo
, but it a class extends C then it is not allowed.
然后final
就可以完成多少覆盖设置了“底线”。其他类可以扩展 A 和 B 并覆盖它们的foo
,但如果类扩展 C 则不允许。
So it probably doesn't make sense to make the 'top-level' foo final
, but it might make sense lower down.
因此,制作“顶级” foofinal
可能没有意义,但可能更有意义。
(I think though, there is room to extend the words final and override to non-virtual members. They would have a different meaning though.)
(不过,我认为还有空间将 final 和 override 一词扩展到非虚拟成员。不过它们会有不同的含义。)
回答by Kerrek SB
final
adds an explicit intent to not have your function overridden, and will cause a compiler error should this be violated:
final
添加一个明确的意图,不让您的函数被覆盖,如果违反,将导致编译器错误:
struct A {
virtual int foo(); // #1
};
struct B : A {
int foo();
};
As the code stands, it compiles, and B::foo
overrides A::foo
. B::foo
is also virtual, by the way. However, if we change #1 to virtual int foo() final
, then this is a compiler error, and we are not allowed to override A::foo
any further in derived classes.
就代码而言,它会编译并B::foo
覆盖A::foo
. B::foo
顺便说一下,也是虚拟的。但是,如果我们将 #1 更改为virtual int foo() final
,那么这是一个编译器错误,我们不允许A::foo
在派生类中进一步覆盖。
Note that this does not allow us to "reopen" a new hierarchy, i.e. there's no way to make B::foo
a new, unrelated function that can be independently at the head of a new virtual hierarchy. Once a function is final, it can never be declared again in any derived class.
请注意,这不允许我们“重新打开”一个新的层次结构,即无法创建B::foo
一个可以独立位于新虚拟层次结构头部的新的、不相关的函数。一旦一个函数是最终的,它就不能在任何派生类中再次声明。
回答by Dan O
The final keyword allows you to declare a virtual method, override it N times, and then mandate that 'this can no longer be overridden'. It would be useful in restricting use of your derived class, so that you can say "I know my super class lets you override this, but if you want to derive from me, you can't!".
final 关键字允许您声明一个虚方法,将其覆盖 N 次,然后强制要求“不能再覆盖”。这对于限制派生类的使用很有用,这样您就可以说“我知道我的超类允许您覆盖它,但是如果您想从我那里派生,则不能!”。
struct Foo
{
virtual void DoStuff();
}
struct Bar : public Foo
{
void DoStuff() final;
}
struct Babar : public Bar
{
void DoStuff(); // error!
}
As other posters pointed out, it cannot be applied to non-virtual functions.
正如其他海报指出的那样,它不能应用于非虚拟功能。
One purpose of the final keyword is to prevent accidental overriding of a method. In my example, DoStuff() may have been a helper function that the derived class simply needs to rename to get correct behavior. Without final, the error would not be discovered until testing.
final 关键字的一个目的是防止意外覆盖方法。在我的示例中, DoStuff() 可能是一个辅助函数,派生类只需重命名即可获得正确的行为。没有final,直到测试才会发现错误。
回答by Krishna Ganeriwal
Final keyword in C++ when added to a function, prevents it from being overridden by a base class. Also when added to a class prevents inheritance of any type. Consider the following example which shows use of final specifier. This program fails in compilation.
C++ 中的 Final 关键字在添加到函数时可防止它被基类覆盖。此外,当添加到类时会阻止任何类型的继承。考虑以下示例,该示例显示了最终说明符的使用。这个程序编译失败。
#include <iostream>
using namespace std;
class Base
{
public:
virtual void myfun() final
{
cout << "myfun() in Base";
}
};
class Derived : public Base
{
void myfun()
{
cout << "myfun() in Derived\n";
}
};
int main()
{
Derived d;
Base &b = d;
b.myfun();
return 0;
}
Also:
还:
#include <iostream>
class Base final
{
};
class Derived : public Base
{
};
int main()
{
Derived d;
return 0;
}
回答by crazii
Supplement to Mario Knezovi? 's answer:
补充马里奥·克内佐维?的回答:
class IA
{
public:
virtual int getNum() const = 0;
};
class BaseA : public IA
{
public:
inline virtual int getNum() const final {return ...};
};
class ImplA : public BaseA {...};
IA* pa = ...;
...
ImplA* impla = static_cast<ImplA*>(pa);
//the following line should cause compiler to use the inlined function BaseA::getNum(),
//instead of dynamic binding (via vtable or something).
//any class/subclass of BaseA will benefit from it
int n = impla->getNum();
The above code shows the theory, but not actually tested on real compilers. Much appreciated if anyone paste a disassembled output.
上面的代码展示了理论,但没有在真正的编译器上实际测试过。如果有人粘贴反汇编的输出,将不胜感激。