7

When I write interface classes in C++, I choose either of the following 2 options

class Interface
{
public:
   virtual R1 f1(p11, p12 , ...) = 0;
   ...
   virtual Rn fn(pn1, pn2 , ...) = 0;
   virtual ~Interface() {} 
}

or

class Interface
{
public:
   virtual R1 f1(p11, p12 , ...) = 0;
   ...
   virtual Rn fn(pn1, pn2 , ...) = 0;
   virtual ~Interface() = 0; 
}
Interface::~Interface() {}

The first version is shorter to write
The second is attractive in that all functions of the interface are pure virtual

Is there any reason I should prefer one or the other method (or perhaps a third one)?
Thanks

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434

4 Answers4

5

As I understand, the purpose of making virtual function pure virtual is to force the derived classes to either provide implementation for it or choose the default implementation by explicitly writing Base::f() in the Derived::f().

So if that is true, then what is the purpose of making virtual destructor pure virtual? Does it force the derived classes to provide implementation for Base::~Base()? Can the derived classes implement Base::~Base()? No.

So that means, the first version with virtual destructor seems enough for almost all purposes. After all, the most common purpose of virtual destructor is that the clients can correctly delete objects of the derived classes through pointers of type Base*.

However, if you make all functions in Base virtual only, not pure virtual, and provide implementations for them (actually you've to provide), and at the same time you want to make Base abstract type, then having a pure virtual destructor in Base is the only solution:

class Base
{
public:
   virtual void f() {}; //not pure virtual
   virtual ~Base() = 0; //pure - makes Base abstract type!
};

Base::~Base() {} //yes, you have to do this as well.

Base *pBase = new Base(); // error - cannot create instance!

Hope that helps.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
2

To me, the dtor is not part of the interface. The fi() would have analogues in other languages, not the dtor. Likewise, you could write pre- and post- conditions for the fi(), but not the dtor. This makes it just a C++ wart, and the first technique is the most comfortable way of dealing with it.

fizzer
  • 13,551
  • 9
  • 39
  • 61
  • 3
    Wart or not, C++ makes the destructor part of the interface. Whether it is virtual or not determines whether clients can validly `delete` an instance of the derived class through a pointer-to-base. Valid client actions == interface. Whether it's pure or not isn't part of the external interface, though, except as Nawaz says if it's the only pure function and hence makes the class abstract. – Steve Jessop Mar 19 '11 at 11:31
  • 1
    I agree, but the question is about virtual versus pure virtual, not virtual versus nonvirtual. – fizzer Mar 19 '11 at 11:42
  • OK, I misunderstood you to mean that in general in C++, dtor is not part of the interface. I agree in this question, the difference between the options offered isn't part of the interface. – Steve Jessop Mar 19 '11 at 12:09
1

In the first case, the derived class may choose whether or not to implement a destructor. In the second case, the pure virtual destructor must be overridden, so the derived class is forced to implement a destructor.

Unless you have some reason why you want to force this, I would go with the first case.

Michael J
  • 7,631
  • 2
  • 24
  • 30
  • 2
    Wrong. The second case doesn't force destructor to be overridden: http://ideone.com/aw3kV . Also, this sentence *"so the base class is forced to implement a destructor"* doesn't make sense to me. Can you rephrase it? – Nawaz Mar 19 '11 at 11:16
  • @Nawaz - Sorry, bad typo. I meant "derived", not "base". It is now fixed. Must stop writing code at 5:00am. – Michael J Mar 20 '11 at 18:24
1

Okay, found a link and so thought I would mention it as an answer:

Are inline virtual functions really a non-sense?

I've seen compilers that don't emit any v-table if no non-inline function at all exists (and defined in one implementation file instead of a header then). They would throw errors like missing vtable-for-class-A or something similar, and you would be confused as hell, as i was.

Indeed, that's not conformant with the Standard, but it happens so consider putting at least one virtual function not in the header (if only the virtual destructor), so that the compiler could emit a vtable for the class at that place. I know it happens with some versions of gcc. (Johannes Schaub)

Its slightly different from your second case (suggests actually taking the function out of the header file altogether so as not to fall victim to gcc problem) but I thought I would mention it. Quirks of gcc can occasionally bite.

Community
  • 1
  • 1
Tom
  • 5,219
  • 2
  • 29
  • 45