C ++中的私有虚拟方法

在C ++中创build一个私有方法的好处是什么?

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

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

香草萨特在这里很好地解释了它。

准则2:倾向于使虚拟function保密。

这可以让派生类重写函数来根据需要自定义行为,而不需要通过派生类来调用虚函数,直接暴露虚函数(如果这些函数只是被保护的话)。 关键是存在虚拟function以允许定制; 除非它们也需要从派生类的代码中直接调用,否则就不需要使它们成为私有的东西

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

(与Prasoon Saurav在他的回答中引用的Herb Sutter相反,C ++ FAQ Lite build议不要使用私有虚拟 ,主要是因为它经常混淆人。)

尽pipe所有的呼吁声明一个虚拟的成员私人,这个论点根本不持有水。 通常,派生类的虚拟函数的重写将不得不调用基类的版本。 它不能,如果它被宣布为private

 class Base { private: int m_data; virtual void cleanup() { /*do something*/ } protected: Base(int idata): m_data (idata) {} public: int data() const { return m_data; } void set_data (int ndata) { m_data = ndata; cleanup(); } }; class Derived: public Base { private: void cleanup() override { // do other stuff Base::cleanup(); // nope, can't do it } public: Derived (int idata): base(idata) {} }; 

必须声明基类方法protected并指示该方法应该被覆盖但不被调用。

 class Base { ... protected: // chained virtual function! // call in your derived version but nowhere else. // Use set_data instead virtual void cleanup() { /* do something */ } ... 

因此,草药萨特的指导方针#3 …但是,马反正在谷仓之外。

当你声明protected东西时,你隐式地相信任何派生类的作者理解和正确使用受保护的内部,而friend声明的方式意味着对private成员更深的信任。

如果用户违反信任(例如,通过不打扰您的文档来标记“无知”),那么他们就只能怪自己了。

更新 :我有一些反馈,声称你可以使用私有虚函数以这种方式“链接”虚函数实现。 如果是这样,我一定会喜欢看的。

我使用的C ++编译器绝对不会让派生类实现调用私有的基类实现。

如果C ++委员会放宽“私人”来允许这个特定的访问,我将全部用于私人虚拟function。 现在,我们仍然被build议在马被盗之后锁上马厩门。

在阅读Scott Meyers的“Effective C ++”时,我首先遇到了这个概念, 第35项:考虑虚拟函数的替代scheme。 我想引用斯科特·迈耶斯(Scott Mayers)为其他可能感兴趣的人。

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

 public: void NonVirtualCalc(...) { // Setup PrivateVirtualCalcCall(...); // Clean up } 

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

  • 为什么使虚拟function是private ? 最好的原因是我们已经提供了一个面向public的方法。
  • 为什么不简单地把它protected以便我可以使用其他有趣的东西的方法? 我想这将总是取决于你的devise以及你相信基类是否适合。我认为派生类的制造者应该把重点放在实现所需的逻辑上; 其他一切已经被照顾了。 另外,还有封装的问题。

从C ++的angular度来看,重写一个私有的虚拟方法是完全合法的,即使你不能从你的类中调用它。 这支持上述devise。

我使用它们来允许派生类为基类“填补空白”,而不会给最终用户带来这样的漏洞。 例如,我有一个高度有状态的对象派生自一个公共的基础,它只能实现2/3的整体状态机(派生类提供剩余的1/3取决于模板参数,基地不能是一个模板其他原因)。

我需要有公共的基类,以使许多公共APIs正常工作(我正在使用可变模板),但我不能让这个对象出来。 更糟糕的是,如果我把状态机中的陨石坑以纯虚拟function的forms留在了“私人”的任何地方,那么我允许一个聪明或者无知的用户从它的一个子类中派生出来覆盖用户不应该触摸的方法。 所以,我把状态机的“大脑”放在了PRIVATE虚拟function中。 然后,基类的直接子对象在它们的非虚拟覆盖上填充空白,用户可以安全地使用结果对象或创build他们自己的派生类,而不用担心搞乱状态机。

至于你不应该公开虚拟方法的论点,我说BS。 用户可以像公开的那样轻易地重写私有虚拟,毕竟他们正在定义新的类。 如果公众不应该修改给定的API,请不要在公共可访问的对象中将其设置为虚拟。