虚方法什么时候应该是纯方法?
我找到了一些我正在处理的代码,并且想知道最好的设计实现是什么。
如果基类将一个方法定义为虚拟方法,但也实现了一个空主体,因此不需要派生类实现主体,那么它不应该成为纯方法吗?
virtual void AMethod1() {} // 1
virtual void AMethod2() {assert(false);} // 2
virtual void AMethod3() = 0; // 3
- 当前代码。
- 想法1:提醒用户该派生对象尚未实现该方法体。
- 想法2:强制派生类实现主体,无论是否为空。
你们这些值得信赖的令人惊叹的SO人怎么想?
Edit1:发布(并阅读答案)后,我意识到断言很糟糕!
virtual void AMethod3() = {throw (ENotImplemented)}; // 4
I have found some code that I am working on, and was wondering what the best design implementation is.
If a base class defines a method as virtual, but implements an empty body as well, thus not requiring the derived classes to implement a body, should it not be made pure instead?
virtual void AMethod1() {} // 1
virtual void AMethod2() {assert(false);} // 2
virtual void AMethod3() = 0; // 3
- Current code.
- Idea1: Alerts user that this derived object has not implemented this method body.
- Idea2: Forces derived classes to implement a body, empty or not.
What do you, the trusted amazing SO people, think?
Edit1: After posting (and reading answers), I realize that assert is bad!
virtual void AMethod3() = {throw (ENotImplemented)}; // 4
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
这在一定程度上取决于您的编码风格的“纯粹”程度。有些人认为您应该始终仅定义一个仅包含纯虚函数的接口,并从中派生所有具体类。
其他人则更加务实,认为如果有一个好的默认实现,您可以将其添加到基类中(选项 1)。
第二个选项似乎最没用,因为它将检测延迟到运行时。大多数程序员宁愿选择选项 3 中的编译错误。
像往常一样,C++ 支持多种范例,您可以选择您喜欢的一种。
It depends a bit on how "pure" your coding style is. Some people believe that you should always define an interface with pure virtual functions only and derive all concrete classes from that.
Others are more pragmatic and belive that if there is a good default implementation, you can add that to the base class (option 1).
The second option seems to be the least useful, as it delays detection until runtime. Most programmers would rather prefer a compilation error from option 3.
As usual, C++ supports several paradigms and you can choose the one you prefer.
如果派生类必须实现此方法,则应使用选项 3。如果在派生类中实现是可选的,则使用选项 1。完全避免选择 2。
You should use option 3 if the derived class must implement this method. Use option 1 if implementing in the derived class is optional. Avoid option 2 altogether.
这取决于您是否想要强制派生类重写该方法。如果你这样做,那么使用纯
虚拟
;它正是满足该要求的语言支持。如果存在或稍后可能存在amethod
的默认实现,则使用带有实现的纯virtual
方法:该函数现在仍然是纯
virtual
因此,Foo
类无法实例化,但任何派生类都将继承该实现,并且其方法可以将其调用为Foo::amethod
。That depends on whether you want to force derived classes to override the method. If you do, then use a pure
virtual
; it's language support for exactly that requirement. If there is or may at a later point be a default implementation ofamethod
, then use a purevirtual
method with an implementation:The function is now still pure
virtual
so theFoo
class cannot be instantiated, but any derived class will inherit the implementation and its methods can call it asFoo::amethod
.使方法纯虚拟比使用断言进行默认实现更直观。在大多数情况下,如果不执行任何操作是默认实现,则当前代码会更好。当然,如果你想使用多态性,它应该保持虚拟。
Making method pure virtual is more intuitive than making default implementation with an assert. Current code is better if doing nothing is default implementation in most cases. Of course it should stay virtual if you want to use polymorphism.
virtual void AMethod1() = 0;
:当您的基类没有提供AND实现时,纯虚拟是最好的这种行为应该被实施。 (这是您问题中的选项 3)virtual void AMethod1() {}
:当您的基类没有提供实现时,具有空实现的虚拟是最好的并且当此行为可以实施时。 (这是您问题中的选项 1)virtual void AMethod1() { assert(false); }
:我认为必须避免带有assert(false)
的虚拟。我没有看到它有任何有效的用途。其背后的基本原理是,所有用例都由上面的两个选项涵盖:实现行为可能或应该,因此定义可调用方法是没有用的那总是失败。编译器可以通过阻止此调用来为您处理该问题,因此此选项通过将此检查推迟到运行时而引入风险。 (这是您问题中的选项2)virtual void AMethod1() = 0;
: A pure virtual is the best when your base class has no implementation to provide AND when this behaviour SHOULD be implemented. (This is option 3 in your question)virtual void AMethod1() {}
: A virtual with an empty implementation is the best when your base class has no implementation to provide AND when this behaviour MAY be implemented. (This is option 1 in your question)virtual void AMethod1() { assert(false); }
: A virtual with anassert(false)
must be avoided in my opinion. I don't see any valid use for it. The rationale behind that being that all use cases are covered by the two options above: either the behaviour may or should is implemented, so there is no use to define a callable method that always fails. The compiler can handle that for you by preventing this call, so this option introduces a risk by postponing this checking to the run time. (This is option 2 in your question)我见过很多这样的例子,你需要实例化类,所以
您使用带有空主体的
virtual
:当您想要强制派生类重写时使用此选项
这个函数,你不需要默认值:
所以这实际上取决于你想要做什么。
I have seen quite a few examples like this where you need to instantiate the class, so
you use
virtual
with a empty body:Use this when you want to force the derived class to override
this function and you don't need a default:
So it really depends on what you want to do.
如果不这样做,我们应该使用纯虚函数
想要实例化一个类但使其充当基类
对于所有从它派生的类。
一件重要的事情
关于纯虚函数需要注意的是这些
必须在所有派生类中重写函数
否则编译会标记出错误。
简单例如,
We should use pure virtual function if we do not
want to instantiate a class but make it act as a base class
for all the classes that derive from it.
An important thing
to note about pure virtual functions is that these
functions must be overridden in all the derived classes
otherwise the compile would flag out an error.
Simple e.g,
这取决于你的设计。如果您的方法是纯虚拟的,您将向派生类开发人员发送一条消息,表示“您必须在此处放置一些实际代码,以便使您的类正常工作”。另一方面,如果您的方法是具有空主体的虚拟方法,则消息是“您可以在此处放置一些代码,但这取决于您的实际需要”。
我肯定更喜欢选项 3 而不是 2,如果派生类没有实现虚拟方法,它将产生编译错误而不是运行时错误。
It depends on your design. If your method is pure virtual you are sending a message to the derived class developer that says 'you must place some actual code here so to make your class work'. On the other hand, if your method is virtual having an empty body, the message is 'you may place some code here, but its up to your actual needs'.
I would definitely prefer option 3 over 2, it will yield a compilation error instead of a run-time error if derived class does not implement the virtual method.
由于您需要
虚拟
机制;以下是我的简短回答:要求:
要求:
要求:
Since you need the
virtual
mechanism; following is my short answer:Requirement:
Requirement:
Requirement:
没有简单的规则:
如果对某些派生类有意义,则使用 1(空实现)
如果调用该函数则不执行任何操作。
如果派生类不实现 3 没有意义,则使用 3
功能。
在极少数情况下使用 2,该函数的前提条件是
另一个虚函数 hare 返回 true,并且该函数有一个
默认实现返回 false (或类似的内容)。
基本上,如果界面的一部分是可选的。 (但通常情况下,
在这种情况下最好派生一个接口;类实现
扩展接口源自它,并且客户端想要使用它
dynamic_cast
到扩展接口。)根据经验(但你的编程风格可能不同),1 似乎适用于至少 90% 的时间,我认为在 C++ 的二十多年中,我'我用过 3 一次,或者两次。
There is no simple rule:
Use 1 (empty implementation) if it makes sense for some derived classes
to do nothing if the function is called.
Use 3 if it doesn't make sense for a derived class not to implement the
function.
Use 2 in the rare case where a precondition of the function is that
another virtual function hare returned true, and that function has a
default implementation to return false (or something along those lines).
Basically, if part of the interface is optional. (But usually, it's
better to derive an interface in such cases; classes implementing the
extended interface derive from it, and clients wanting to use it
dynamic_cast
to the extended interface.)From experience (but your programming style may be different), 1 seems to apply at least 90% of the time, and I think in over twenty years of C++, I've used 3 once, or maybe twice.