为什么虚拟功能是私有的?

时间:2009-07-15 20:49:10

标签: c++ private virtual-functions access-specifier function-overriding

我刚才在一些代码中发现了这一点:

class Foo {
[...]
private:
    virtual void Bar() = 0;
[...]
}

这有什么用途吗?

(我试图将一些代码从VS移植到G ++,这引起了我的注意)

8 个答案:

答案 0 :(得分:22)

请参阅this Herb Sutter article了解您为什么要这样做。

答案 1 :(得分:10)

这是一个纯粹的虚拟功能,恰好是私有的。这使得派生类必须实现该方法。在这种情况下,Bar。

我认为你可能会感到困惑b / c这是为了在C ++中创建“接口”,很多时候人们都认为这些是公共的。在某些情况下,您可能希望定义一个私有接口,其中公共方法使用这些私有方法,以确保它们的调用顺序。 (我相信这被称为模板方法)

对于一个相对糟糕的例子:)

class RecordFile
{
    public:
       RecordFile(const std::string &filename);

       void process(const Record &rec)
       {
           // Call the derived class function to filter out
           // records the derived instance of this class does
           // not care about
           if (filterRecord(rec))    
           {
               writeRecordToFile(rec);           
           }
       };

    private:
       // Returns true if the record is of importance
       // and should be kept
       virtual bool filterRecord(const Record &rec) = 0;

       void writeRecordToFile(const Record &rec);
};

答案 2 :(得分:9)

ISO C ++ 2003明确允许它:

§10.3没有说明访问说明符,并且在第二个子句中包含一个脚注,在虚函数覆盖的上下文中说明:

  

[...]访问控制(第11条)是   没有考虑确定   覆盖。

代码完全合法。

答案 3 :(得分:5)

我将引用伟大的C++ FAQ Lite的简短解释,总结得很好:

  

[23.4]有人应该何时使用私人   虚函数?

     

几乎没有。

     

受保护的虚拟可以,但是   私人虚拟通常是网络   失利。原因:私人虚拟混淆   新的C ++程序员,以及混乱   增加成本,延迟时间表和   降低风险。

     

新的C ++程序员感到困惑   私人虚拟,因为他们认为   私有虚拟无法被覆盖。   毕竟,派生类不能   访问其中的私有成员   基类,他们问,怎么样呢   从其中覆盖私有虚拟   基类?有解释   以上,但这是学术上的。该   真正的问题是几乎每个人   他们第一次跑步时会感到困惑   进入私人虚拟和混乱   很糟糕。

     

除非有令人信服的理由   相反,避免私人虚拟。


C ++ FAQ Lite在此期间更新:

  

顺便说一下,它让大多数新手C ++程序员感到困惑,私有虚拟可以被覆盖,更不用说有效了。我们都被告知基类中的私有成员在从它派生的类中是不可访问的,这是正确的。但是,派生类的这种不可访问性与虚拟调用机制没有任何关系,虚拟调用机制与派生类有关。由于这可能会混淆新手,以前建议使用受保护虚拟而非私有虚拟的C ++ FAQ。然而,私有虚拟方法现在足够普遍,新手的混淆不再是一个问题。

答案 4 :(得分:5)

通常的“学术”答案是:访问说明符和虚拟性是正交的 - 一个不影响另一个。

更实际的答案:私有虚函数通常用于实现Template Method设计模式。在不支持私有虚函数的语言中,模板方法需要公开,尽管它并不真正意味着是接口的一部分。

答案 5 :(得分:2)

这是一个纯虚函数。任何源自“Food”的最终实现必须实现“Bar”功能。

答案 6 :(得分:1)

它使函数纯虚拟而不是虚拟。

默认情况下不提供任何实现,目的是必须由继承类指定函数实现。但是,这可以被覆盖。

您有时会看到完整的类,其中所有成员函数都以这种方式指定为纯虚拟。

这些是抽象基类,有时也称为接口类,ABC的设计者对你说,“我现在已经知道如何为这个基类的所有特化实现这个功能。但是,你必须将所有这些定义为您的专业化工作,并且您知道您的对象应该如何表现“。

编辑:哎呀,刚刚发现成员纯虚函数是私有的。 (谢谢Michael)这会稍微改变一下。

当使用私有继承继承此基类时,它会更改内容。基本类的设计者基本上就是说,当你的派生类在基类中调用非私有函数时。部分行为已委派给派生类中的函数专门化。非私有成员正在做“某事”,而“某事”的一部分是通过纯虚拟基类函数调用到您的实现。

因此,Foo中的一些公共函数正在调用Foo中的Bar函数,并且它依赖于您将为您的特定情况提供Bar函数的专门实现。

斯科特迈耶斯将此称为“以”来实施“。

顺便说一句,对于那些在问题中没有看到“细则”的人迅速删除的答案数量感到轻笑! ( - :

HTH

欢呼声,

答案 7 :(得分:0)

它似乎服务的唯一目的是提供一个通用接口。

BTW即使函数被声明为私有虚拟,它仍然可以通过类实例或朋友来实现和调用。

尽管如此,这种事情通常意味着作为界面,但我不是这样做的。