173

Is it wrong to write:

class A {
public:
    virtual ~A() = 0;
};

for an abstract base class?

At least that compiles in MSVC... Will it crash at run time?

Alex Bitek
  • 6,529
  • 5
  • 47
  • 77
Ivan Krechetov
  • 18,802
  • 8
  • 49
  • 60

2 Answers2

229

Yes. You also need to implement the destructor:

class A {
public:
    virtual ~A() = 0;
};

inline A::~A() { }

should suffice.

If you derive anything from A and then try to delete or destroy it, A's destructor will eventually be called. Since it is pure and doesn't have an implementation, undefined behavior will ensue. On one popular platform, that will invoke the purecall handler and crash.

Edit: fixing the declaration to be more conformant, compiled with http://www.comeaucomputing.com/tryitout/

miken32
  • 42,008
  • 16
  • 111
  • 154
MSN
  • 53,214
  • 7
  • 75
  • 105
  • So it should be declared virtual ~A() { }, without the "= 0". It's not pure virtual if you provide an implementation – jalf Mar 10 '09 at 16:16
  • 16
    Um, yes it is. Pure only means a derived class also needs to provide an implementation. – MSN Mar 10 '09 at 16:24
  • 78
    Implementing pure virtual functions is in fact legal. Very useful for providing a default implementation but forcing subclasses to call it explicitly. – jmucchiello Mar 10 '09 at 16:47
  • 6
    MSN and note if you have that definition in the header, you need to put "inline" before it to avoid violating the ODR (one definition rule) – Johannes Schaub - litb Mar 10 '09 at 17:04
  • 2
    Why does A::~A() have to be explicitly defined, since, I thought there is a default destructor for every object? As in any type of inheritance, the chain of destructors is always called and the base class destructor doesn't have to always be defined. – jeffD Mar 11 '09 at 17:47
  • 2
    The base class destructor always has to be defined if it will be invoked. If you never delete or explicitly destroy sublcasses of A, this doesn't matter. If you do, it does. – MSN Mar 11 '09 at 18:51
  • 11
    A better way to put it is that once you declare a destructor, it is not automatically implemented for you. – MSN Mar 11 '09 at 21:36
  • If you don't provide a definition for `A::~A()`, you should get a compile-time error—a link error. – bobbogo Feb 06 '17 at 11:50
  • @MSN , what do you mean by this undefined behavior and crash? https://pastebin.com/Uz2Ny4z0 This program does not crash on Windows. Is that the popular platform? The output is: https://pastebin.com/PJNdktPY – BriarPatch Jul 13 '17 at 17:17
  • @bobbogo "If you don't provide a definition for A::~A(), you should get a compile-time" -- not possible to see for the compiler. Only linker will detect it. – Wolf Aug 31 '17 at 10:16
  • 1
    Would I, according to [this cpp core guideline](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all) need to `=default` the other special member methods as well? – LCsa Sep 29 '18 at 16:13
  • Just a node: even though you "force" the derived class to declare the destructor by making it pure, it will be OK to have a derived class without any (user defined) destructor. https://godbolt.org/z/x7Tcko – Machta Jan 07 '19 at 16:50
  • 1
    Look at [this](https://stackoverflow.com/a/2001942/5825294), I did not know that you could write `virtual ~A() = 0 {};`. – Enlico Nov 20 '20 at 09:14
49

Private destructors: they will give you an error when you create an object of a derived class -- not otherwise. A diagnostic may appear though.

12.4 Destructors

6 A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.

A class with a pure virtual destructor is an abstract class. Note well:

10.4 Abstract classes

2 A pure virtual function need be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1).

[Note:a function declaration cannot provide both a pure-specifier and a definition —end note ]

Taken straight from the draft:

struct C {
   virtual void f() = 0 { }; // ill-formed
};
dirkgently
  • 108,024
  • 16
  • 131
  • 187