"undefined reference to vtable": What the Linker Is Telling You and How to Fix It
Key takeaways
"undefined reference to vtable for X" names a class, not the function you forgot. GCC and Clang emit a vtable next to the class's key function, its first non-inline, non-pure virtual function, so a missing or unlinked definition of that one function makes the whole table disappear. How to find it, and the other causes: a declared but undefined destructor, a .cpp missing from the build, and Qt classes that moc never processed.
Why this error is confusing
struct Base {
virtual void foo(); // declared, never defined
virtual ~Base() {}
};
int main() { Base b; }
ld: main.o:main.cpp:(.rdata$.refptr._ZTV4Base[.refptr._ZTV4Base]+0x0): undefined reference to `vtable for Base'
collect2.exe: error: ld returned 1 exit status
That is GCC 10 on MinGW. On Linux the same code typically reports it “in function Base::Base()'", pointing at the constructor. _ZTV4Base is the mangled name of the vtable (_ZTV` means “vtable for”). Most “undefined reference” errors name the function you forgot to define. This one names a table you never wrote, and often points at a constructor you never wrote either. To fix it quickly you need to know two things: what the vtable is, and which object file is supposed to contain it.
What the vtable is and who uses it
For a class with virtual functions, the compiler generates a table of function pointers, one per virtual function, pointing at the implementation for that class. Every object of the class carries a hidden pointer to that table (the vptr). A virtual call p->foo() loads the vptr, looks up foo’s slot and calls whatever it finds.
The code that sets the vptr is the constructor. That is why the error appears “in function `Base::Base()’” or a derived constructor: constructing an object is the moment the program needs the address of the table. If you never construct an object of the class, you usually get no error at all, even with every virtual function missing.
The key function rule
A class’s vtable has to be emitted in some object file. If every translation unit that includes the header emitted it, you would get many copies. The Itanium C++ ABI, used by GCC and Clang on Linux, macOS and MinGW, solves this with a rule:
The vtable is emitted in the translation unit that defines the class’s key function: the first virtual function declared in the class that is neither inline nor pure virtual.
If the class has no key function (every virtual function is inline or pure), the vtable is emitted in every translation unit that needs it, as a mergeable weak symbol.
This is why forgetting to define one particular function removes the entire table. The compiler sees virtual void foo();, decides foo is the key function, and assumes whichever .cpp defines Base::foo will emit the vtable. If no such .cpp exists, nobody emits it.
You can see the rule at work with two nearly identical classes. With GCC 10:
struct A { virtual void foo(); virtual void bar() {} virtual ~A() {} };
int main() { A a; }
// undefined reference to `vtable for A'
foo is the first non-inline virtual function, so it is the key function, and without its definition the table is missing.
struct B { virtual void foo(); virtual void bar(); };
void B::foo() {}
int main() { B b; }
// undefined reference to `B::bar()'
Here the key function foo is defined, so the vtable is emitted. It contains a pointer to bar, which is missing, and the linker names bar directly. Same mistake, different message, depending only on which function you forgot.
Cause 1: the key function is declared but never defined
// shape.h
class Shape {
public:
virtual double area() const; // key function
virtual ~Shape() {}
};
Nobody wrote double Shape::area() const { ... }. Either define it in shape.cpp, or, if every Shape subclass must provide its own, make it pure: virtual double area() const = 0;. A pure virtual function is never a key function and needs no definition (the destructor is the exception, below).
Cause 2: a declared virtual destructor with no body
class Base {
public:
virtual ~Base(); // declared, never defined
virtual void foo() {}
};
undefined reference to `Base::~Base()'
undefined reference to `vtable for Base'
This is probably the most common real-world version. The destructor is often the first declared virtual function, so it becomes the key function. Fix it either in the header, virtual ~Base() = default; (inline, so no longer a key function), or in base.cpp, Base::~Base() = default;.
Pure virtual destructors are a special case. virtual ~Base() = 0; is not a key function, but it still needs a definition, because every derived destructor calls it. Forgetting that gives undefined reference to Base::~Base(), and the fix is the same out-of-line Base::~Base() = default;.
Cause 3: the definition exists but is not linked
Everything is written correctly, and the error remains. The .cpp holding the key function is:
- not listed in
add_executable/add_libraryin CMake, or in the Makefile’s object list; - compiled into a static library that is linked before the objects that use it (with GNU ld, order matters: libraries must come after the objects that need them);
- guarded by an
#ifdefthat is false in this configuration.
A fast check is to look for the symbol in the object files. On Linux, nm -C shape.o | grep vtable shows whether vtable for Shape is defined (any letter other than U, typically R or V) or only referenced (U). If no object file defines it, go back to cause 1 or 2; if one does but it is not on the link line, it is a build problem.
Cause 4: Qt classes and moc
In Qt projects, adding Q_OBJECT to a class declares several virtual functions (metaObject(), qt_metacall() and others) whose definitions are generated by the meta-object compiler. If moc did not process the header, those definitions do not exist, and the result is “undefined reference to vtable for MyWidget”. Typical triggers are adding Q_OBJECT to a class in a file the build system was not scanning, or a class defined in a .cpp without the corresponding #include "file.moc". Re-running qmake or enabling CMAKE_AUTOMOC, then rebuilding, usually fixes it.
A related case: class templates
If a class template’s virtual functions are defined in a .cpp instead of the header, the member functions are never instantiated for the types you use. The vtable of a template instantiation is emitted wherever it is needed, so here the linker usually names the missing members (undefined reference to Box<int>::draw()) rather than the table. Define class template members in the header, or explicitly instantiate the types you need in the .cpp.
MSVC is different
MSVC does not use a key function. It emits the vtable in every translation unit that needs it, so the table itself is never missing. Instead you see the specific function, for example LNK2001: unresolved external symbol "public: virtual void __cdecl Base::foo(void)". The underlying mistakes are the same; only the diagnostic is clearer.
Where this goes wrong in practice
The case that costs me the most time is not a forgotten definition but a forgotten file. Someone adds widget.cpp with the constructor and all the virtual function bodies, forgets to add it to the CMake target, and the build fails with “undefined reference to vtable for Widget” instead of the dozen “undefined reference to Widget::…” errors that would have made the cause obvious. When every function looks defined and the error persists, I now check the target’s source list before re-reading the class.
The other is a destructor declared “to be filled in later”. A class gets virtual ~Parser(); in the header with the intent to write the body when resources are added, and it links fine for weeks because nothing constructs a Parser yet. The first test that does construct one fails with a vtable error in a constructor nobody wrote, which looks unrelated to a destructor at all. Writing = default at the declaration avoids the delayed surprise.
A quick diagnostic sequence
- List the class’s virtual functions in declaration order, including the destructor.
- Find the first one that is not defined in the class body and not
= 0. That is the key function. - Search for its definition (
ClassName::function). - If it exists, confirm its
.cppis compiled and on the link line. - For Qt classes with
Q_OBJECT, rerun moc (qmake / AUTOMOC).