简体   繁体   中英

Why do I get a linker error?

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.

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.

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.

You're declaring a function

  void func()

Which is shadowing the method

void MyClass::func()

So your call is calling the undefined function, rather than the method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM