Why does this virtual destructor trigger an unresolved external?

Greg D picture Greg D · Aug 24, 2010 · Viewed 12.4k times · Source

Consider the following:

In X.h:

class X
{
    X();
    virtual ~X();
};

X.cpp:

#include "X.h"

X::X()
{}

Try to build this (I'm using a .dll target to avoid an error on the missing main, and I'm using Visual Studio 2010):

Error 1 error LNK2001: unresolved external symbol "private: virtual __thiscall X::~X(void)" (??1X@@EAE@XZ)

Small modifications result in a successful build, however:

X.h:

class X
{
    inline X(); // Now inlined, and everything builds
    virtual ~X();
};

or

X.h:

class X
{
    X();
    ~X(); // No longer virtual, and everything builds
};

What causes the unresolved external in the linker when the .dtor is virtual or when the .ctor isn't inlined?

EDIT:

Or, perhaps more interestingly, why do I not get an unresolved external if I make the destructor non-virtual, or if I inline the constructor?

Answer

Martin York picture Martin York · Aug 24, 2010

Situation 1:

You have the code for the constructor.
So it builds the constructor into the object file. The constructor needs the address of the destructor to put into the virtual table because it can not find it the constructor can not be built.

Situation 2: (inline constructor)

The compiler decides it does not need to build the constructor (as it will be inlined).
As such it does not plant any code and therefore does not need the address of the destructor.

If you instanciate an object of type X it will again complain.

Situation 3: (non virtual destructor)

You don't need the address of the destructor to build the constructor.
So it does not complain.

It will complain if you instantiate an object of type X.