私有纯虚函数的意义何在?
我在头文件中发现了以下代码:
I came across the following code in a header file:
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;
};
对我来说,这意味着 Engine
类或从它派生的类必须为那些纯虚函数提供实现.但我不认为派生类可以访问这些私有函数来重新实现它们――那么为什么要让它们成为虚拟的呢?
To me, this implies that either the Engine
class or a class derived from it, has to provide the implementation for those pure virtual functions. But I didn't think derived classes could have access to those private functions in order to reimplement them - so why make them virtual?
推荐答案
该主题中的问题暗示了一个非常常见的混淆.这种混淆很常见,C++ FAQ 长期以来一直反对使用私有虚拟机,因为混淆似乎是坏事.
The question in the topic suggest a pretty common confusion. The confusion is common enough, that C++ FAQ advocated against using private virtuals, for a long time, because confusion seemed to be a bad thing.
所以首先要摆脱混乱:是的,可以在派生类中覆盖私有虚拟函数.派生类的方法不能从基类调用虚函数,但可以为它们提供自己的实现.根据 Herb Sutter 的说法,在基类中具有公共非虚拟接口和可以在派生类中自定义的私有实现,可以更好地将接口规范与实现的可定制行为规范分离".您可以在他的文章虚拟化"中阅读更多相关信息.
So to get rid of the confusion first: Yes, private virtual functions can be overridden in the derived classes. Methods of derived classes can't call virtual functions from the base class, but they can provide their own implementation for them. According to Herb Sutter, having public non-virtual interface in the base class and a private implementation that can be customized in the derived classes, allows for better "separation of the specification of interface from the specification of the implementation's customizable behavior". You can read more about it in his article "Virtuality".
然而,在我看来,您提供的代码中还有一件更有趣的事情,值得更多关注.公共接口由一组重载的非虚函数组成,这些函数调用非公共、非重载的虚函数.在 C++ 世界中,它是一个惯用语,它有一个名字,当然它很有用.名字是(惊喜,惊喜!)
There is however one more interesting thing in the code you presented, that deserves some more attention, in my opinion. The public interface consists of a set of overloaded non-virtual functions and those functions call non-public, non-overloaded virtual functions. As usual in the C++ world it is an idiom, it has a name and of course it is useful. The name is (surprise, surprise!)
公共重载非虚拟调用受保护的非重载虚拟"
"Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals"
有助于正确管理隐藏规则.您可以在此处阅读更多相关信息,但我会尝试简单解释一下.
It helps to properly manage the hiding rule. You can read more about it here, but I'll try to explain it shortly.
想象一下,Engine
类的虚函数也是它的接口,它是一组非纯虚的重载函数.如果它们是纯虚拟的,仍然会遇到同样的问题,如下所述,但在类层次结构中较低.
Imagine, that virtual functions of the Engine
class are also its interface and it is a set of overloaded functions that is not pure virtual. If they were pure virtual, one could still encounter the same problem, as described below, but lower in the class hierarchy.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
现在让我们假设您要创建一个派生类,并且您只需要为该方法提供一个新的实现,它接受两个整数作为参数.
Now let's assume you want to create a derived class and you need to provide a new implementation only for the method, that takes two ints as arguments.
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 声明放在派生类中(或重新定义第二个重载),您可能会在下面的场景中遇到麻烦.
If you forgot to put the using declaration in the derived class (or to redefine the second overload), you could get in trouble in the scenario below.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
如果您没有阻止隐藏 Engine
成员,则声明:
If you didn't prevent the hiding of the Engine
members, the statement:
myV8->SetState(5, true);
会从派生类调用void SetState(int var, int val)
,将true
转换为int
.
would call void SetState( int var, int val )
from the derived class, converting true
to int
.
如果接口不是虚拟的并且虚拟实现是非公共的,就像你的例子一样,派生类的作者少了一个问题,可以简单地写
If the interface is not virtual and the virtual implementation is non-public, like in your exmaple, the author of the derived class has one less problem to think about and can simply write
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};
相关文章