将结构前向声明为类时出现 Visual C++ 2015 链接器错误
Posted
技术标签:
【中文标题】将结构前向声明为类时出现 Visual C++ 2015 链接器错误【英文标题】:Visual C++ 2015 linker error when forward declaring a struct as class 【发布时间】:2015-11-02 17:40:01 【问题描述】:我有以下代码(涉及多个文件)...
//--- 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 xstd::make_shared<SomeInterfaceImpl>();
使用 Visual C++ 编译器时,出现链接器错误 (LNK2019)。使用 GCC 4.8.4 并非如此。将前向声明 class SomeInterface 更改为 struct SomeInterface 会使链接器错误消失。我一直认为应该能够互换使用类/结构? SomeInterfaceUser 的接口不应该取决于 SomeInterface 是定义为 class 还是 struct,不是吗?
这是一个 Visual C++ 错误。我找不到任何与之相关的东西。我怀疑结构被用作模板参数的事实与它有关。
感谢您的帮助。
【问题讨论】:
这里似乎工作正常。请发布您的所有编译器和链接器设置,并确保您已正确发布所有文件内容。 @ChristianHackl。我有一个相当复杂的项目,但是将前向声明从结构更改为类不应使链接器错误消失。您是否已将各种类移到各自的文件中? 那么,这个错误是只发生在您的复杂项目中,还是您发布的示例代码也会发生? @Christian Hackl。该示例是一个简化。老实说,我得看看。 我以前见过这种情况,并且总是通过前向声明和使用相同的关键字声明它们来解决问题。我认为这与 MSVC 破坏名称的方式有关。 【参考方案1】:我刚刚在使用 VC++ 2010 和 VC++ 2017 时遇到了同样的问题,经过一些测试,我发现问题在于编译器在内部赋予结构和类的符号名称。
这是一个包含三个文件的最小示例:
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)
编译项目时出现以下错误和警告:
警告 C4099:“Foo”:第一次看到使用“类”的类型名称现在使用“结构”看到
参见“Foo”的声明
错误 LNK2019:函数 _main 中引用的无法解析的外部符号“void __cdecl bar(struct Foo *)”(?bar@@YAXPAUFoo@@@Z)
致命错误 LNK1120:1 个未解决的外部问题
现在,我交换了 struct
和 class
声明,所以 main.cpp
和 bar.h
现在是:
main.cpp
#include "bar.h"
class Foo ;
int main()
Foo foo;
bar(&foo);
return 0;
bar.h
struct Foo;
void bar(Foo* f);
果然还是报错:
错误 LNK2019:函数 _main 中引用的无法解析的外部符号“void __cdecl bar(class Foo *)”(?bar@@YAXPAVFoo@@@Z)
但是,这是有趣的部分,请注意每种情况下预期函数(main()
中使用的那个)的符号不同:
?bar@@YAXPAUFoo@@@Z(当参数为struct
时)
?bar@@YAXPAVFoo@@@Z(当参数为class
时)
结论
如果类型是结构或类,编译器会给出稍微不同的名称。
然后链接器找不到正确的定义,因为它正在寻找不同的定义:bar.cpp
使用前向声明定义了一个,但目前在 main.cpp
中调用它时,实际声明已经发生,所以符号表中给出了不同的函数名称。
【讨论】:
刚刚碰到同样的问题,我花了 2~3 个小时才弄清楚原因。从来没有想过 MSVC(VS 2017) 会因此而区分到发出链接器错误的地步。以上是关于将结构前向声明为类时出现 Visual C++ 2015 链接器错误的主要内容,如果未能解决你的问题,请参考以下文章
解读将 Visual C++ 6 项目升级到 Visual Studio 2008 时出现的错误
C++ - 将 C++ 代码从 Visual Studio 移植到 Linux Eclipse IDE 时出现问题