fre*_*low 53 c++ inheritance virtual-functions final c++11
维基百科在C++ 11 final修饰符上有以下示例:
struct Base2 {
virtual void f() final;
};
struct Derived2 : Base2 {
void f(); // ill-formed because the virtual function Base2::f has been marked final
};
Run Code Online (Sandbox Code Playgroud)
我不明白引入虚拟功能并立即将其标记为最终功能.这只是一个不好的例子,还是有更多的东西?
bam*_*s53 58
通常final不会在基类的虚函数定义中使用.final将由覆盖该函数的派生类使用,以防止进一步的派生类型进一步覆盖该函数.由于覆盖函数必须是正常的虚拟,这意味着任何人都可以在另一个派生类型中覆盖该函数.final允许一个人指定一个覆盖另一个但不能被覆盖的函数.
例如,如果您正在设计类层次结构并需要覆盖函数,但您不希望允许类层次结构的用户执行相同操作,那么您可能会在派生类中将函数标记为final.
它对我来说似乎没用.我认为这只是演示语法的一个例子.
一种可能的用法是,如果你不希望f真正被重写,但你仍然想要生成vtable,但这仍然是一种可怕的做事方式.
对于要标记的函数,final它必须是virtual,即在C++11§10.3段中.2:
[...]为方便起见,我们说任何虚函数都会覆盖自己.
和第4段:
如果某个类B中的虚函数f用virt-specifier final标记,并且在从B派生的类D中,函数D :: f会覆盖B :: f,则该程序是格式错误的.[...]
ie,final只需要与虚函数(或使用类来阻止继承)一起使用.因此,该示例需要virtual用于它是有效的C++代码.
编辑:完全清楚:"点"询问关于虚拟甚至使用的问题.使用它的底线原因是(i)因为代码不会编译,并且,(ii)为什么在一个人满足时使用更多类使示例更复杂?因此,使用具有虚拟最终函数的一个类作为示例.
添加到上面的好答案 - 这是一个著名的 Final 应用程序(很大程度上受到 Java 的启发)。假设我们在基类中定义了一个函数 wait(),并且我们只希望在其所有后代中实现 wait() 一个。在这种情况下,我们可以将 wait() 声明为final。
例如:
class Base {
public:
virtual void wait() final { cout << "I m inside Base::wait()" << endl; }
void wait_non_final() { cout << "I m inside Base::wait_non_final()" << endl; }
};
Run Code Online (Sandbox Code Playgroud)
这是派生类的定义:
class Derived : public Base {
public:
// assume programmer had no idea there is a function Base::wait()
// error: wait is final
void wait() { cout << "I am inside Derived::wait() \n"; }
// that's ok
void wait_non_final() { cout << "I am inside Derived::wait_non_final(); }
}
Run Code Online (Sandbox Code Playgroud)
如果 wait() 是纯虚函数,那么它将是无用的(并且不正确)。在这种情况下:编译器将要求您在派生类中定义 wait()。如果你这样做,它会给你一个错误,因为 wait() 是最终的。
为什么最终函数应该是虚函数?(这也让人困惑)因为(imo)1)final的概念和虚函数的概念非常接近【虚函数有多种实现——final函数只有一种实现】,2)很容易实现final效果使用虚函数表。
我不明白引入虚函数并立即将其标记为最终函数的意义。
该示例的目的是说明如何final工作,它就是这样做的。
一个实际目的可能是查看 vtable 如何影响类的大小。
struct Base2 {
virtual void f() final;
};
struct Base1 {
};
assert(sizeof(Base2) != sizeof(Base1)); //probably
Run Code Online (Sandbox Code Playgroud)
Base2可以简单地用于测试平台细节,没有必要覆盖,f()因为它只是用于测试目的,所以它被标记为final. 当然,如果你这样做,设计上就有问题。我个人不会创建一个带有virtual函数的类只是为了检查vfptr.
在重构遗留代码时(例如,从母类中删除一个虚拟方法),这有助于确保没有子类使用这个虚拟函数。
// Removing foo method is not impacting any child class => this compiles
struct NoImpact { virtual void foo() final {} };
struct OK : NoImpact {};
// Removing foo method is impacting a child class => NOK class does not compile
struct ImpactChildClass { virtual void foo() final {} };
struct NOK : ImpactChildClass { void foo() {} };
int main() {}
Run Code Online (Sandbox Code Playgroud)