在 C++ 中用私有函数覆盖公共虚拟函数;
是否有任何理由使重写的 C++ 虚函数的权限与基类不同? 这样做有危险吗?
例如:
class base {
public:
virtual int foo(double) = 0;
}
class child : public base {
private:
virtual int foo(double);
}
C++ 常见问题 说这是一个坏主意,但没有说明原因。
我在一些代码中看到了这种习惯用法,并且我相信作者试图将类设为最终类,基于不可能重写私有成员函数的假设。 但是,本文展示了重写私有函数的示例。 当然,C++ 常见问题解答的另一部分推荐反对这样做。
我的具体问题:
在派生类与基类中对虚拟方法使用不同的权限是否存在任何技术问题?
这样做有什么正当理由吗?
Is there is any reason to make the permissions on an overridden C++ virtual function different from the base class? Is there any danger in doing so?
For example:
class base {
public:
virtual int foo(double) = 0;
}
class child : public base {
private:
virtual int foo(double);
}
The C++ faq says that it is a bad idea, but doesn't say why.
I have seen this idiom in some code and I believe that the author was attempting to make the class final, based on an assumption that it is not possible to override a private member function. However, This article shows an example of overriding private functions. Of course another part of the C++ faq recommends against doing so.
My concrete questions:
Is there any technical problem with using a different permission for virtual methods in derived classes vs base class?
Is there any legitimate reason to do so?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
你确实得到了令人惊讶的结果,如果你有一个孩子,你不能调用 foo,但你可以将它转换为基数,然后调用 foo。
我想您也许可以设计一个示例,在该示例中您不希望公开函数,除非您将其视为基类的实例。 但这种情况的出现本身就表明在某个地方存在着糟糕的面向对象设计,可能应该进行重构。
You do get the surprising result that if you have a child, you can't call foo, but you can cast it to a base and then call foo.
I suppose you might be able to contrive an example where you don't want a function exposed, except when you are treating it as an instance of the base class. But the very fact that that situation pops up would suggest a bad OO design somewhere along the line that should probably be refactored.
问题在于基类方法是声明其接口的方式。 从本质上讲,它是在说“这些是您可以对此类对象执行的操作”。
当你在派生类中创建一些被基类声明为公有私有的东西时,你就拿走了一些东西。 现在,即使派生对象“是”基对象,您应该能够对基类对象执行的操作却无法对派生类对象执行,从而破坏了 里氏替换原理
这会导致您的程序出现“技术”问题吗? 也许不会。 但这可能意味着您的类的对象不会按照用户期望的方式运行。
如果您发现自己处于您想要的情况(除了另一个答案中提到的已弃用方法的情况),很可能您有一个继承模型,其中继承并不是真正建模“is-a”,(例如,Scott Myers 的示例 Square 继承自 Rectangle,但您无法像矩形那样独立于其高度来更改 Square 的宽度),并且您可能需要重新考虑您的类关系。
The problem is that the Base class methods are its way of declaring its interface. It is, in essence saying, "These are the things you can do to objects of this class."
When in a Derived class you make something the Base had declared as public private, you are taking something away. Now, even though a Derived object "is-a" Base object, something that you should be able to do to a Base class object you cannot do to a Derived class object, breaking the Liskov Substitution Prinicple
Will this cause a "technical" problem in your program? Maybe not. But it will probably mean object of your classes won't behave in a way your users expect them to behave.
If you find yourself in the situation where this is what you want (except in the case of a deprecated method referred to in another answer), chances are you have an inheritance model where inheritance isn't really modeling "is-a," (e.g. Scott Myers's example Square inheriting from Rectangle, but you can't change a Square's width independent of its height like you can for a rectangle) and you may need to reconsider your class relationships.
没有技术问题,但您最终会遇到这样一种情况:公开可用的函数将取决于您是否有基指针或派生指针。
在我看来,这会很奇怪且令人困惑。
There's no technical problem, but you will end up with a situation where the publicly available functions will depend upon whether you have a base or derived pointer.
This in my opinion would be weird and confusing.
如果您使用私有继承,它会非常有用 - 即您想要重用基类的(定制)功能,而不是接口。
It can be very useful if you are using private inheritance - i.e. you want to reuse a (customized) functionality of a base class, but not the interface.
这是可以做到的,而且偶尔会带来好处。 例如,在我们的代码库中,我们正在使用一个库,其中包含一个具有公共函数的类,我们曾经使用过该函数,但现在由于其他潜在问题而不鼓励使用(有更安全的方法可以调用)。 我们还碰巧有一个从该类派生的类,我们的许多代码都直接使用它。 因此,我们在派生类中将给定的函数设为私有,以帮助每个人记住如果可以的话就不要使用它。 它并没有消除使用它的能力,但它会在代码尝试编译时(而不是稍后在代码审查中)捕获一些用途。
It can be done, and very occasionally will lead to benefits. For example, in our codebase, we are using a library that contains a class with a public function that we used to use, but now discourage the use of due to other potential problems (there are safer methods to call). We also happen to have a class derived from that class which a lot of our code uses directly. So, we made the given function private in the derived class in order to help everyone remember not to use it if they can help it. It doesn't eliminate the ability to use it, but it will catch some uses when the code tries to compile, rather than later in the code reviews.
私有继承的一个很好的用例是侦听器/观察者事件接口。
私有对象的示例代码:
该对象的一些用户想要父功能,而另一些用户想要子功能:
这样
AnimationList
可以保存对父功能的引用并使用父功能。 而Seal
保留对子级的引用并使用独特的子级功能并忽略父级的功能。 在此示例中,Seal
不应调用Animate
。 现在,如上所述,可以通过转换为基础对象来调用 Animate,但这更加困难,通常不应该这样做。A good use-case for private inheritance is a Listener/Observer event interface.
Example code for the private object:
Some users of the object want the parent functionality and some want the child functionality:
This way the
AnimationList
can hold a reference to the parents and uses parent functionality. While theSeal
holds a reference to the child and uses the unique child functionality and ignoring the parent's. In this example, theSeal
shouldn't callAnimate
. Now, as mentioned above,Animate
can be called by casting to the base object, but that's more difficult and generally shouldn't be done.