如何为类定义"最终"成员函数

Hem*_*ant 17 c++

是否可以final像在Java中一样创建我的成员函数,以便派生类不能覆盖它们?

Jef*_*den 23

C++ 11添加了一个finalcontextual关键字来支持这个:

class B
{
  public:
    virtual void foo() final;
};
class D : B
{
  public:
    virtual void foo(); // error: declaration of 'foo' overrides a 'final' function
};
Run Code Online (Sandbox Code Playgroud)

finalGCC 4.7和Clang 3.0支持.正如Sergius在他的回答中指出的那样sealed,自MSVC++ 2005以来,MSVC++支持它(拼写).因此,如果您封装在一个迷你宏中并根据您的编译器进行设置,那么您可以使用它.只要确保你实际上至少每隔一段时间使用这样的编译器,这样你就可以及早发现任何错误.


Pét*_*rök 9

它实际上是默认行为.即如果你没有明确地声明你的类实例方法virtual,它们不能在子类中被覆盖(只有隐藏,这是一个不同的 - 几乎总是错误的 - 情况).

有效的C++第三版,第36项详细论述了这一点.考虑

class B {
public:
  virtual void vf();
  void mf();
  virtual void mf(int);
  ...
};

class D: public B {
public:
  virtual void vf();              // overrides B::vf
  void mf();                      // hides B::mf; see Item33
  ...
};

D x;                              // x is an object of type D
B *pB = &x;                       // get pointer to x
D *pD = &x;                       // get pointer to x

pD->vf();                         // calls D::mf, as expected
pB->vf();                         // calls D::mf, as expected
pD->mf();                         // calls D::mf, as expected
pB->mf();                         // calls B::mf - surprise!
pD->mf(1);                        // error -  D::mf() hides B::mf(int)!
pB->mf(1);                        // calls B::mf(int)
Run Code Online (Sandbox Code Playgroud)

所以这并不完全是finalJava中的行为,但是你只能用C++来实现这一点.另一种方法可能是完全阻止子类化.技术 - 工作,但不是很好 - 解决方案是声明所有构造函数private(并提供静态工厂方法,如果你想允许实例化你的类,当然).

  • 还有另一个阻止继承的技巧,即添加一个虚拟基类,它(a)有一个私有构造函数,(b)声明你的类是一个"朋友".虚拟基础的构造函数必须可由最派生类访问,因此无法实例化类的任何派生类(尽管可以定义它).但是,您的类可以实例化,因此与您的版本不同,您最终不会使用仅限堆的类.可以作为CRTP模板完成.缺点:可能会使对象更大. (2认同)