When should a virtual method be pure?
Asked Answered
V

10

9

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
  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
Vinosity answered 27/7, 2011 at 11:3 Comment(6)
Note, that you can actually have a pure virtual method with a body (it just can't be inline).Gudrin
Could you elaborate on why you consider assert as worse than an exception? In the case at hand, I find it quite appropriate: if the method must always be overriden and the base class never instantiated, then the default implementation should never be called, this is an invariant of the program (not an event that can exceptionnaly occurs). Of course, if these are the requirements, you are better off making the method pure virtual.Murr
@Let_Me_Be thanks for that, I think larsmans gave an answer with an example of what you say...Vinosity
@Luc Touraille Maybe because assert() is checked in debug mode only, it is usually switched off in release build.Deary
@Archie: I am not sure this is really an issue here since the assert will only be useful during development (it is aimed at developers extending the base class). It is used to warn developers that there is an error in their design, once it is corrected the assert should not be triggered ever after, so there should be no harm in switching it off afterwards.Murr
@Luc Touraille: It is correct if all pathes of execution are covered in tests -- that isn't true sometimes, moreover: in rare cases it becomes impossible. It is more safe to throw error; we can determine where exactly is the error, regardless of compilation mode; if assertion is omitted an error may happen everywhere and become very painful. I'd say throw UnimplementedException is more safe even in release code and much more readable than assertion.Deary
S
9

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.

Soggy answered 27/7, 2011 at 11:11 Comment(1)
"it delays detection until runtime" - which would be more useful if (and I think only if) there are situations where you'd create an object and use other member functions, but avoid calling AMethod2. Probably a design flaw, since if you're restricted to using only a subset of the defined API, maybe you should have formally defined another, smaller interface. But it flies.Reeder
G
6

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.

Gerome answered 27/7, 2011 at 11:6 Comment(2)
I sorta know that, I was wondering if there was a preferred implementation design? But its as you say in your other answer, it depends on coding styleVinosity
@Ian: I don't really think this is a matter of coding style, but more of semantics: does having a default implementation makes sense? Does it make sense to instantiate the class? Do I want the default implementation to be implicitely used if there is no override, or should the derived classes implicitely invoke it if they want to use it? (Well, that last question is perhaps only a matter of style). There can not really be a preffered design since they do not achieve the same goals: choosing one or the other depends on what your requirements are.Murr
U
3

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.

Unbeatable answered 27/7, 2011 at 11:7 Comment(3)
Ohh, I didnt know I could do pure virtual with an implementation! virtual void Foo::amethod() Thanks.Vinosity
larsmans thanks for the nice example but you will still have to overried the pure virtual function in derived class even though now you can simply call the implmented pure virutal function in the derive class as a default if that's what you want.something like: class derived : public Foo{ public: void amethod(){ // still need override here Foo::amethod(); } };Caernarvonshire
@Gob00st: that's right, it's still pure virtual. I'll clarify my answer a bit.Unbeatable
O
2

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.

Oiler answered 27/7, 2011 at 11:11 Comment(0)
C
2

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.

Caernarvonshire answered 27/7, 2011 at 11:16 Comment(0)
M
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 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)

Mealymouthed answered 27/7, 2011 at 11:23 Comment(0)
Q
1

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();
   }
Quarto answered 27/7, 2011 at 11:6 Comment(1)
I think that hits the nail on the head pure virtual if not want to instantiate a class but act base class.Vinosity
B
1

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
Ballad answered 27/7, 2011 at 11:11 Comment(0)
C
1

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.

Cashmere answered 27/7, 2011 at 11:21 Comment(0)
S
0

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.

Stylograph answered 27/7, 2011 at 12:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.