将结构前向声明为类时出现 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 时遇到了同样的问题,经过一些测试,我发现问题在于编译器在内部赋予结构和类的符号名称。

这是一个包含三个文件的最小示例:

ma​​in.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 个未解决的外部问题

现在,我交换了 structclass 声明,所以 main.cppbar.h 现在是:

ma​​in.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 时出现问题

将声明的枚举转发为类成员变量

Visual C++ 2017,外部“C”被忽略了吗?将 C++ 代码链接到 C 库时出现 LNK2019 错误

类前向声明​​失败,没有递归包含

尝试使用 Visual Studio 2010 调试 dll (C++) 时出现错误消息