Undefined reference to vtable

前端 未结 16 2115
死守一世寂寞
死守一世寂寞 2020-11-21 20:30

When building my C++ program, I\'m getting the error message

undefined reference to \'vtable...

What is the cause of this probl

相关标签:
16条回答
  • 2020-11-21 21:23

    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:

    1. A member function is missing its definition.
    2. An object file is not being linked.
    3. 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! :)

    1. 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.
    2. Find the definition for that function. If it is missing, add it! (Error possibly resolved.)
      • See also the answer by RedSpikeyThing for a caveat.
    3. Check your link command. If it does not mention the object file with that function's definition, fix that! (Error possibly resolved.)
    4. 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.)

    0 讨论(0)
  • 2020-11-21 21:24

    I just ran into another cause for this error that you can check for.

    The base class defined a pure virtual function as:

    virtual int foo(int x = 0);
    

    And the subclass had

    int foo(int x) override;
    

    The problem was the typo that the "=0" was supposed to be outside of the parenthesis:

    virtual int foo(int x) = 0;
    

    So, in case you're scrolling this far down, you probably didn't find the answer - this is something else to check for.

    0 讨论(0)
  • 2020-11-21 21:26

    Not to cross post but. If you are dealing with inheritance the second google hit was what I had missed, ie. all virtual methods should be defined.

    Such as:

    virtual void fooBar() = 0;
    

    See answare C++ Undefined Reference to vtable and inheritance for details. Just realized it's already mentioned above, but heck it might help someone.

    0 讨论(0)
  • 2020-11-21 21:26

    I think it's also worth mentioning that you will also get the message when you try to link to object of any class that has at least one virtual method and linker cannot find the file. For example:

    Foo.hpp:

    class Foo
    {
    public:
        virtual void StartFooing();
    };
    

    Foo.cpp:

    #include "Foo.hpp"
    
    void Foo::StartFooing(){ //fooing }
    

    Compiled with:

    g++ Foo.cpp -c
    

    And main.cpp:

    #include "Foo.hpp"
    
    int main()
    {
        Foo foo;
    }
    

    Compiled and linked with:

    g++ main.cpp -o main
    

    Gives our favourite error:

    /tmp/cclKnW0g.o: In function main': main.cpp:(.text+0x1a): undefined reference tovtable for Foo' collect2: error: ld returned 1 exit status

    This occure from my undestanding becasue:

    1. Vtable is created per class at compile time

    2. Linker does not have access to vtable that is in Foo.o

    0 讨论(0)
  • 2020-11-21 21:28

    So, I've figured out the issue and it was a combination of bad logic and not being totally familiar with the automake/autotools world. I was adding the correct files to my Makefile.am template, but I wasn't sure which step in our build process actually created the makefile itself. So, I was compiling with an old makefile that had no idea about my new files whatsoever.

    Thanks for the responses and the link to the GCC FAQ. I will be sure to read that to avoid this problem occurring for a real reason.

    0 讨论(0)
  • 2020-11-21 21:28

    Undefined reference to vtable may occur due to the following situation also. Just try this:

    Class A Contains:

    virtual void functionA(parameters)=0; 
    virtual void functionB(parameters);
    

    Class B Contains:

    1. The definition for the above functionA.
    2. The definition for the above functionB.

    Class C Contains: Now you're writing a Class C in which you are going to derive it from Class A.

    Now if you try to compile you will get Undefined reference to vtable for Class C as error.

    Reason:

    functionA is defined as pure virtual and its definition is provided in Class B. functionB is defined as virtual (NOT PURE VIRTUAL) so it tries to find its definition in Class A itself but you provided its definition in Class B.

    Solution:

    1. Make function B as pure virtual (if you have requirement like that) virtual void functionB(parameters) =0; (This works it is Tested)
    2. Provide Definition for functionB in Class A itself keeping it as virtual . (Hope it works as I didn't try this)
    0 讨论(0)
提交回复
热议问题