TL;DR - Explains why the vtable might be missing and how to fix it. The answer is long because it explains why the compiler might forget to create a vtable. (Editor)
What is a vtable
?
It might be useful to know what the error message is talking about before trying to fix it. I'll start at a high level, then work down to some more details. That way people can skip ahead once they are comfortable with their understanding of vtables. …and there goes a bunch of people skipping ahead right now. :) For those sticking around:
A vtable is basically the most common implementation of polymorphism in C++. When vtables are used, every polymorphic class has a vtable somewhere in the program; you can think of it as a (hidden) static
data member of the class. Every object of a polymorphic class is associated with the vtable for its most-derived class. By checking this association, the program can work its polymorphic magic. Important caveat: a vtable is an implementation detail. It is not mandated by the C++ standard, even though most (all?) C++ compilers use vtables to implement polymorphic behavior. The details I am presenting are either typical or reasonable approaches. Compilers are allowed to deviate from this!
Each polymorphic object has a (hidden) pointer to the vtable for the object's most-derived class (possibly multiple pointers, in the more complex cases). By looking at the pointer, the program can tell what the "real" type of an object is (except during construction, but let's skip that special case). For example, if an object of type A
does not point to the vtable of A
, then that object is actually a sub-object of something derived from A
.
The name "vtable" comes from "virtual function table". It is a table that stores pointers to (virtual) functions. A compiler chooses its convention for how the table is laid out; a simple approach is to go through the virtual functions in the order they are declared within class definitions. When a virtual function is called, the program follows the object's pointer to a vtable, goes to the entry associated with the desired function, then uses the stored function pointer to invoke the correct function. There are various tricks for making this work, but I won't go into those here.
Where/when is a vtable
generated?
A vtable is automatically generated (sometimes called "emitted") by the compiler. A compiler could emit a vtable in every translation unit that sees a polymorphic class definition, but that would usually be unnecessary overkill. An alternative (used by gcc, and probably by others) is to pick a single translation unit in which to place the vtable, similar to how you would pick a single source file in which to put a class' static data members. If this selection process fails to pick any translation units, then the vtable becomes an undefined reference. Hence the error, whose message is admittedly not particularly clear.
Similarly, if the selection process does pick a translation unit, but that object file is not provided to the linker, then the vtable becomes an undefined reference. Unfortunately, the error message can be even less clear in this case than in the case where the selection process failed. (Thanks to the answerers who mentioned this possibility. I probably would have forgotten it otherwise.)
The selection process used by gcc makes sense if we start with the tradition of devoting a (single) source file to each class that needs one for its implementation. It would be nice to emit the vtable when compiling that source file. Let's call that our goal. However, the selection process needs to work even if this tradition is not followed. So instead of looking for the implementation of the entire class, let's look for the implementation of a specific member of the class. If tradition is followed – and if that member is in fact implemented – then this achieves the goal.
The member selected by gcc (and potentially by other compilers) is the first non-inline virtual function that is not pure virtual. If you are part of the crowd that declares constructors and destructors before other member functions, then that destructor has a good chance of being selected. (You did remember to make the destructor virtual, right?) There are exceptions; I'd expect that the most common exceptions are when an inline definition is provided for the destructor and when the default destructor is requested (using "= default
").
The astute might notice that a polymorphic class is allowed to provide inline definitions for all of its virtual functions. Doesn't that cause the selection process to fail? It does in older compilers. I've read that the latest compilers have addressed this situation, but I do not know relevant version numbers. I could try looking this up, but it's easier to either code around it or wait for the compiler to complain.
In summary, there are three key causes of the "undefined reference to vtable" error:
- A member function is missing its definition.
- An object file is not being linked.
- All virtual functions have inline definitions.
These causes are by themselves insufficient to cause the error on their own. Rather, these are what you would address to resolve the error. Do not expect that intentionally creating one of these situations will definitely produce this error; there are other requirements. Do expect that resolving these situations will resolve this error.
(OK, number 3 might have been sufficient when this question was asked.)
How to fix the error?
Welcome back people skipping ahead! :)
- Look at your class definition. Find the first non-inline virtual function that is not pure virtual (not "
= 0
") and whose definition you provide (not "= default
").
- If there is no such function, try modifying your class so there is one. (Error possibly resolved.)
- See also the answer by Philip Thomas for a caveat.
- Find the definition for that function. If it is missing, add it! (Error possibly resolved.)
- Check your link command. If it does not mention the object file with that function's definition, fix that! (Error possibly resolved.)
- Repeat steps 2 and 3 for each virtual function, then for each non-virtual function, until the error is resolved. If you're still stuck, repeat for each static data member.
Example
The details of what to do can vary, and sometimes branch off into separate questions (like What is an undefined reference/unresolved external symbol error and how do I fix it?). I will, though, provide an example of what to do in a specific case that might befuddle newer programmers.
Step 1 mentions modifying your class so that it has a function of a certain type. If the description of that function went over your head, you might be in the situation I intend to address. Keep in mind that this is a way to accomplish the goal; it is not the only way, and there easily could be better ways in your specific situation. Let's call your class A
. Is your destructor declared (in your class definition) as either
virtual ~A() = default;
or
virtual ~A() {}
? If so, two steps will change your destructor into the type of function we want. First, change that line to
virtual ~A();
Second, put the following line in a source file that is part of your project (preferably the file with the class implementation, if you have one):
A::~A() {}
That makes your (virtual) destructor non-inline and not generated by the compiler. (Feel free to modify things to better match your code formatting style, such as adding a header comment to the function definition.)
qmake -project
and thenqmake
) to generate a newMakefile
, that is a likely source of the error when using Qt. – David C. RankinQ_OBJECT
is copied externally, but not yet part of the .pro file, then though it compiles fine, it doesn't link. We have to add that.h/.cpp
file into the .pro file to be able toqmake
. – iammilind