What is an undefined reference/unresolved external symbol error and how do I fix it?

What are undefined reference/unresolved external symbol errors? What are common causes, and how do I fix and prevent these errors?

  • 1

    @jave.web: While that does happen, the programmer usually notices that he has no this pointer and no access to class members. It’s quite rare to complete compilation and only fail during linking, when a non-static member function is missing its qualified-name.

    – 

  • 2

    @jave.web: This was exactly my problem. Thank you! I am new to cpp, but as far as I can tell, I was having the exact problem that Ben Voigt says was quite rare. I think your solution would make a great answer.

    – 




  • 1

    @Snaptastic see stackoverflow.com/a/12574407/673730 – A common mistake is forgetting to qualify the name 🙂

    – 

  • 9

    They may be useful, just as are many answers to questions that are flagged as too general.

    – 

  • 3

    I would like to see minimal reproducible example as something we ask of most new users , honestly. I don’t mean anything by it, it is just – we can’t expect people to follow the rules we don’t inforce onto ourselves.

    – 




Class members:

A pure virtual destructor needs an implementation.

Declaring a destructor pure still requires you to define it (unlike a regular function):

struct X
{
    virtual ~X() = 0;
};
struct Y : X
{
    ~Y() {}
};
int main()
{
    Y y;
}
//X::~X(){} //uncomment this line for successful definition

This happens because base class destructors are called when the object is destroyed implicitly, so a definition is required.

virtual methods must either be implemented or defined as pure.

This is similar to non-virtual methods with no definition, with the added reasoning that
the pure declaration generates a dummy vtable and you might get the linker error without using the function:

struct X
{
    virtual void foo();
};
struct Y : X
{
   void foo() {}
};
int main()
{
   Y y; //linker error although there was no call to X::foo
}

For this to work, declare X::foo() as pure:

struct X
{
    virtual void foo() = 0;
};

Non-virtual class members

Some members need to be defined even if not used explicitly:

struct A
{ 
    ~A();
};

The following would yield the error:

A a;      //destructor undefined

The implementation can be inline, in the class definition itself:

struct A
{ 
    ~A() {}
};

or outside:

A::~A() {}

If the implementation is outside the class definition, but in a header, the methods have to be marked as inline to prevent a multiple definition.

All used member methods need to be defined if used.

A common mistake is forgetting to qualify the name:

struct A
{
   void foo();
};

void foo() {}

int main()
{
   A a;
   a.foo();
}

The definition should be

void A::foo() {}

static data members must be defined outside the class in a single translation unit:

struct X
{
    static int x;
};
int main()
{
    int x = X::x;
}
//int X::x; //uncomment this line to define X::x

An initializer can be provided for a static const data member of integral or enumeration type within the class definition; however, odr-use of this member will still require a namespace scope definition as described above. C++11 allows initialization inside the class for all static const data members.

Leave a Comment