What is the point of a private pure virtual function?
我在头文件中遇到了以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 | class Engine { public: void SetState( int var, bool val ); { SetStateBool( int var, bool val ); } void SetState( int var, int val ); { SetStateInt( int var, int val ); } private: virtual void SetStateBool(int var, bool val ) = 0; virtual void SetStateInt(int var, int val ) = 0; }; |
对我来说,这意味着无论是
这个主题中的问题暗示了一个相当普遍的困惑。这种混淆是常见的,C++FAQ提倡使用私人虚拟,长期以来,因为混淆似乎是一件坏事。
因此,为了首先摆脱混乱:是的,私有虚拟函数可以在派生类中被重写。派生类的方法不能从基类调用虚拟函数,但它们可以为它们提供自己的实现。根据Herb Sutter的说法,在基类中有公共的非虚拟接口,在派生类中有一个可以定制的私有实现,允许更好地"将接口规范与实现的可定制行为规范分离开来"。你可以在他的文章"虚拟性"中了解更多。
然而,在我看来,在您所提供的代码中还有一个更有趣的东西需要更多的关注。公共接口由一组重载的非虚拟函数组成,这些函数调用非公共的非重载虚拟函数。与C++一样,它是一个成语,它有一个名字,当然它是有用的。名字是(惊喜,惊喜!)
"公共重载非虚拟调用受保护的非重载虚拟"
它有助于正确管理隐藏规则。你可以在这里读到更多关于它的信息,但我会尽快解释。
想象一下,
1 2 3 4 5 6 | class Engine { public: virtual void SetState( int var, bool val ) {/*some implementation*/} virtual void SetState( int var, int val ) {/*some implementation*/} }; |
现在让我们假设您想要创建一个派生类,并且您只需要为方法提供一个新的实现,它使用两个ints作为参数。
1 2 3 4 5 6 7 8 9 10 | class MyTurbochargedV8 : public Engine { public: // To prevent SetState( int var, bool val ) from the base class, // from being hidden by the new implementation of the other overload (below), // you have to put using declaration in the derived class using Engine::SetState; void SetState( int var, int val ) {/*new implementation*/} }; |
如果忘记将using声明放在派生类中(或重新定义第二个重载),在下面的场景中可能会遇到麻烦。
1 2 | MyTurbochargedV8* myV8 = new MyTurbochargedV8(); myV8->SetState(5, true); |
如果您没有阻止隐藏
1 | myV8->SetState(5, true); |
从派生类调用
如果接口不是虚拟的,并且虚拟实现是非公共的,就像在您的ExMaple中一样,派生类的作者有一个较少的问题需要考虑,可以简单地编写
1 2 3 4 5 | class MyTurbochargedV8 : public Engine { private: void SetStateInt(int var, int val ) {/*new implementation*/} }; |
型
私有纯虚拟函数是非虚拟接口习惯用法的基础(好吧,它不是绝对的纯虚拟,但仍然是虚拟的)。当然,这也用于其他事情,但我发现这是最有用的(:用两个词来说:在公共函数中,您可以在函数的开头和结尾放置一些常见的东西(如日志、统计信息等),然后在中间调用这个私有虚拟函数,这对于特定的派生函数来说是不同的。类。比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class Base { // .. public: void f(); private: virtual void DerivedClassSpecific() = 0; // .. }; void Base::f() { //.. Do some common stuff DerivedClassSpecific(); //.. Some other common stuff } // .. class Derived: public Base { // .. private: virtual void DerivedClassSpecific(); //.. }; void Derived::DerivedClassSpecific() { // .. } |
纯虚拟-只要求派生类实现它。
编辑:关于此的详细信息:维基百科::nvi习语
型
首先,这将允许派生类实现基类(包含纯虚函数声明)可以调用的函数。
型
编辑:阐明有关重写能力和访问/调用能力的语句。
它将能够覆盖这些私有功能。例如,下面的人为示例有效(编辑:使派生类方法私有化,并在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include <iostream> class Engine { public: void SetState( int var, bool val ) { SetStateBool( var, val ); } void SetState( int var, int val ) { SetStateInt( var, val ); } private: virtual void SetStateBool(int var, bool val ) = 0; virtual void SetStateInt(int var, int val ) = 0; }; class DerivedEngine : public Engine { private: virtual void SetStateBool(int var, bool val ) { std::cout <<"DerivedEngine::SetStateBool() called" << std::endl; } virtual void SetStateInt(int var, int val ) { std::cout <<"DerivedEngine::SetStateInt() called" << std::endl; } }; int main() { DerivedEngine e; Engine * be = &e; be->SetState(4, true); be->SetState(2, 1000); } |
号
类中的
型
私有虚拟方法用于限制可以重写给定函数的派生类的数量。必须重写私有虚拟方法的派生类必须是基类的朋友。
可以找到devx.com的简要说明。
在模板方法模式中,有效地使用了私有虚拟方法。派生类可以重写私有虚拟方法,但派生类不能调用它的基类私有虚拟方法(在您的示例中,
关于虚拟性,可以找到一篇有趣的文章。