开发者

When should a virtual method be pure?

I have found some code that I am working on, and wa开发者_Python百科s 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
  1. Current code.
  2. Idea1: Alerts user that this derived object has not implemented this method body.
  3. 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


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.


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.


If a base class defines a method as virtual, but implements a empty body as well, thus not requiring the derived classes from implementing a body, should it not be made pure instead?

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 of amethod, then use a pure virtual method with an implementation:

class Foo {
    virtual void amethod() = 0;
};

void Foo::amethod() {
    // whatever
}

The function is now still pure virtual so the Foo class cannot be instantiated, but any derived class will inherit the implementation and its methods can call it as Foo::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;: 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 an assert(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)


I have seen quite a few examples like this where you need to instantiate the class, so you use virtual with a empty body:

virtual void AMethod1() {}                 // 1

Use this when you want to force the derived class to override this function and you don't need a default:

virtual void AMethod3() = 0;               // 3

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,

class alpha     {
     public:virtual void show()=0; //pure virtual function
    };

class beta : public alpha {

     public:void show()   //overriding
        {
         cout<<"OOP in C++";
        }
    };
void main() {
     alpha *p;
     beta b;
     p=&b;
     p->show();
   }


If a base class defines a method as virtual, but implements a empty body as well, thus not requiring the derived classes from implementing a body, should it not be made pure instead?

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'.

virtual void AMethod1() {}                 // 1
virtual void AMethod2() {assert(false);}   // 2
virtual void AMethod3() = 0;               // 3

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:

(1) virtual void AMethod1() {}

Requirement:

- Allow creating objects of base class
- Base `virtual` method is use.

(2) virtual void AMethod2() {assert(false);}

Requirement:

- Allow creating objects of base class
- Base method is not used
- Force derived classes to implement the method (hard way, because it happens at runtime).

(3) virtual void AMethod3() = 0;

Requirement:

- Don't allow base class object creation
- Force derived classes to implement the method at compile time


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜