Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get a linker error?

Tags:

c++

Why do I get a linker error?

/*
test.cpp
© Andrey Bushman, 18 Jun 2013
*/
//--------------------------------------------
#include <exception>
#include <iostream>
using namespace std;
//--------------------------------------------
namespace Bushman{
//--------------------------------------------
    class MyClass{
    public:
        MyClass();
    };
//--------------------------------------------
    MyClass::MyClass(){
        void func(); // declaration
        func(); // call
    }
//--------------------------------------------
    void func(){ // definition
        cout << "Ping..." << endl;
    }
}
//============================================
int main()
try{
    namespace B = Bushman;
    B::MyClass a;
}
catch(exception& e){
    cerr << e.what() << endl;
    return 1;
}
catch(...){
    cerr << "Unknown exception." << endl;
    return 2;
}

Result (by MS Visual Studio 2012):

C:\bs\13>cl test.cpp /EHsc
Microsoft (R) C/C++ Optimizing Compiler
Version 17.00.51106.1 for x64 Copyright (C) Microsoft Corporation. All
rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 11.00.51106.1
Copyright (C) Microsoft Corporation. All rights reserved.

/out:test.exe test.obj test.obj : error LNK2019: unresolved external
symbol "void __cdecl func(void)" ( ?func@@YAXXZ) referenced in
function "public: __cdecl Bushman::MyClass::MyClass( void)"
(??0MyClass@Bushman@@QEAA@XZ) test.exe : fatal error LNK1120: 1
unresolved externals

C:\bs\13>

Thank you.

like image 750
Andrey Bushman Avatar asked Nov 21 '25 10:11

Andrey Bushman


2 Answers

It looks like your compiler is erroneously introducing the name into the global namespace, rather than the innermost enclosing namespace (Bushman) as specified by C++11 3.5/7:

When a block scope declaration of an entity with linkage is not found to refer to some other declaration, then that entity is a member of the innermost enclosing namespace.

The code compiles as expected on GCC: http://ideone.com/PR4KVC

You should be able to work around the bug by declaring the function in the correct namespace before (or instead of) declaring it in the constructor's block scope. However, I don't have access to your compiler to test that.

like image 188
Mike Seymour Avatar answered Nov 23 '25 01:11

Mike Seymour


namespace Bushman{
    MyClass::MyClass(){
        void func(); // declaration
        func(); // call
    }
    //--------------------------------------------
    void func(){ // definition
        cout << "Ping..." << endl;
    }
}

You declare func() inside the MyClass constructor. This should be the same as the func() you defined in the Bushman namespace; but it appears that your compiler gets that wrong. Generally declaring a function inside another function or inside a constructor is considered bad practice. Instead you should declare functions directly in the scope where you intend them to be. In this case, you need a forward declaration of func() inside the Bushman namespace:

namespace Bushman{
    void func(); // declaration

    MyClass::MyClass(){
        func(); // call
    }

    //--------------------------------------------
    void func(){ // definition
        cout << "Ping..." << endl;
    }
}

Alternatively, you can split your code into separate .h and .cpp files. In fact, this is ideal. I suggest putting func() in func.cpp with a declaration in func.h. Similarly put the MyClass declaration in myclass.h and the MyClass definitions in myclass.cpp. Now myclass.cpp should `#include "func.h".

Using header files this way gives you fine-tuned control over forward declarations and ensures that everything is defined when it is needed.

like image 29
Code-Apprentice Avatar answered Nov 23 '25 01:11

Code-Apprentice