关于多态:C++中的私有虚拟方法

Private virtual method in C++

在C++中实现私有方法的优点是什么?

我在开源C++项目中注意到了这一点:

1
2
3
4
5
class HTMLDocument : public Document, public CachedResourceClient {
private:
    virtual bool childAllowed(Node*);
    virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};


Herb Sutter在这里很好地解释了这一点。

准则2:倾向于使虚拟功能私有化。

这样,派生类就可以根据需要重写函数来定制行为,而不必通过使派生类可以调用虚拟函数来直接公开它们(如果函数只是受保护的话,这是可能的)。关键是,虚拟函数的存在允许定制;除非它们也需要直接从派生类的代码中调用,否则不需要将它们设置为私有的。


如果方法是虚拟的,它可以被派生类重写,即使它是私有的。调用虚方法时,将调用重写的版本。

(与Prasoon Saurav引用的Habor萨特的回答相反,C++FAQ Lite建议反对私人虚拟,主要是因为它经常使人迷惑。)


(P)请所有人宣布一个虚拟会员私人,这只是一个争论,不拥有水。Frequently,a derived class's override of a virtual function will have to call the base class version.如果它被宣布为"EDOCX1",它就不会是(p)字母名称(P)你必须宣布基础分类方法EDOCX1的英文。(p)(P)Then,you have to take the ugly carrient of indicating via a comment that the method should be overridden but not called.(p)字母名称(P)Thus herb sutter's guideline§35;3…But the horse is out of the barn anyway.(p)(P)当你宣布某个以东X1的标语1时,你将意味着任何起源类别的作者必须理解和充分利用受保护的内部,仅仅是一种途径A以东X1的标语3。(p)(P)Users who get bad behavior from violating that trust(e.g.labeled'cluels'by not bothering to read your documentation)have only themselves to blame.(p)(P)Update:I've had some feedback that claims you can"chain"virtual function implementations this way using private virtual functions.如果这样的话,我会看到它。(p)(P)The C++compilers I use definitely won't let a derived class implementation call a private base class implementation.(p)(P)如果C++Committee relaxed"private"to allow this specific access,I'd be all for private virtual functions.作为一个站,我们仍然是一个顾问,在时间停止后,把Barn Door锁起来。(p)


我首先在阅读Scott Meyers的"有效C++"时遇到这个概念,第35项:考虑虚拟函数的替代。我想向斯科特·梅耶斯推荐其他可能感兴趣的人。

它是模板方法模式的一部分,通过非虚拟接口习语:面向公共的方法不是虚拟的;相反,它们包装了私有的虚拟方法调用。然后,基类可以在私有虚拟函数调用之前和之后运行逻辑:

1
2
3
4
5
6
7
public:
  void NonVirtualCalc(...)
  {
    // Setup
    PrivateVirtualCalcCall(...);
    // Clean up
  }

我认为这是一个非常有趣的设计模式,我确信您可以看到添加的控件是如何有用的。

  • 为什么要使虚函数private?最好的原因是我们已经提供了一个面向public的方法。
  • 为什么不简单地把它设置为protected,这样我就可以把这个方法用于其他有趣的事情呢?我想这将永远取决于你的设计以及你如何相信基类适合。我认为派生类生成器应该集中于实现所需的逻辑;其他的一切都已经得到了处理。另外,还有封装问题。

从C++的角度来看,重写私有虚拟方法是完全合法的,即使您不能从类调用它。这支持上述设计。


我使用它们来允许派生类为基类"填充空白",而不向最终用户暴露这样一个漏洞。例如,我有从公共基派生的高状态对象,它只能实现整个状态机的2/3(派生类根据模板参数提供剩余的1/3,而基不能是其他原因的模板)。< BR>

为了使许多公共API正常工作(我使用的是variadic模板),我需要有一个公共的基类,但是我不能让这个对象失控。更糟糕的是,如果我把环形山放在状态机中(以纯虚拟函数的形式),而不是放在"私有"中的任何地方,我允许从它的一个子类派生的聪明或无知的用户覆盖用户永远不应该接触的方法。所以,我把状态机"大脑"放在私有的虚拟功能中。然后,基类的直接子类在它们的非虚拟重写上填充空白,用户可以安全地使用生成的对象或创建自己的进一步派生类,而不必担心弄乱状态机。< BR>

至于不应该使用公共虚拟方法的论点,我说是B。用户可以不正确地覆盖私有虚拟,就像公共虚拟一样容易——毕竟他们正在定义新的类。如果公众不应该修改一个给定的API,那么就不要在公共可访问的对象中使其成为虚拟的。