I have the following code (more than one file involved)...
//--- SomeInterface.h
struct SomeInterface
{
virtual void foo() = 0;
virtual ~SomeInterface(){}
};
//--- SomeInterfaceUser.h
#include <memory> //shared_ptr
class SomeInterface;
//NOTE: struct SomeInterface... causes linker error to go away...
class SomeInterfaceUser
{
public:
explicit SomeInterfaceUser(std::shared_ptr<SomeInterface> s);
};
//SomeInterfaceUser.cpp
#include "SomeInterfaceUser.h"
#include "SomeInterface.h"
SomeInterfaceUser::SomeInterfaceUser(std::shared_ptr<SomeInterface> s)
{
}
//SomerInterfaceUserInstantiator.cpp
#include "SomeInterfaceUser.h"
#include "SomeInterfaceImpl.h"
struct SomeInterfaceImpl : SomeInterface
{
virtual void foo(){}
};
void test()
{
SomeInterfaceUser x{std::make_shared<SomeInterfaceImpl>()};
}
Using the Visual C++ compiler, I get a linker error (LNK2019). Using GCC 4.8.4 this is not the case. Changing the forward declaration class SomeInterface to struct SomeInterface makes the linker error go away. I always thought that one should be able to use class/struct interchangeably? The interface of SomeInterfaceUser should not depend on whether SomeInterface is defined as class or struct, not so?
Is this a Visual C++ bug. I cannot find anything relating to it. I suspect the fact that the struct is used as template parameter has something to do with it.
Your help appreciated.
In Visual Studio, make sure the source file that defines the symbol gets compiled as part of your project. Check the intermediate build output directory for a matching . obj file. If the source file isn't compiled, right-click on the file in Solution Explorer and choose Properties to check the properties of the file.
In C++, classes and structs can be forward-declared like this: class MyClass; struct MyStruct; In C++, classes can be forward-declared if you only need to use the pointer-to-that-class type (since all object pointers are the same size, and this is what the compiler cares about).
The unresolved external symbol is a linker error that indicates it cannot find the symbol or its reference during the linking process. The error is similar to “undefined reference” and is issued interchangeably.
I've just been facing the same problem with both VC++ 2010 and VC++ 2017, and after some tests I've found that the problem resides in the symbol name the compiler gives to structs and classes internally.
Here a minimum example consisting in three files:
main.cpp
#include "bar.h"
struct Foo {};
int main() {
Foo foo;
bar(&foo);
return 0;
}
bar.h
class Foo;
void bar(Foo* f);
bar.cpp
#include "bar.h"
void bar(Foo* foo) {}
When the project is compiled the following errors and warnings appear:
warning C4099: 'Foo': type name first seen using 'class' now seen using 'struct'
see declaration of 'Foo'
error LNK2019: unresolved external symbol "void __cdecl bar(struct Foo *)" (?bar@@YAXPAUFoo@@@Z) referenced in function _main
fatal error LNK1120: 1 unresolved externals
Now, I swapped the struct
and class
declarations, so main.cpp
and bar.h
are now:
main.cpp
#include "bar.h"
class Foo {};
int main() {
Foo foo;
bar(&foo);
return 0;
}
bar.h
struct Foo;
void bar(Foo* f);
As expected, the error still pops up:
error LNK2019: unresolved external symbol "void __cdecl bar(class Foo *)" (?bar@@YAXPAVFoo@@@Z) referenced in function _main
BUT, and this is the interesting part, see that the symbols for the expected function (the one used in main()
) in each case differ:
?bar@@YAXPAUFoo@@@Z (when the parameter is a struct
)
?bar@@YAXPAVFoo@@@Z (when the parameter is a class
)
Conclusion
The compiler gives slightly different names if the type is a struct or a class.
The linker then cannot find the proper definition because it is looking for a different one: bar.cpp
defines one with the forward declaration, but for the moment it is called in main.cpp
the actual declaration has taken placed, so a different function name is given in the symbols table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With