向前将结构声明为类时出现Visual C ++ 2015链接器错误

Wer*_*mus 6 c++ visual-c++

我有以下代码(涉及多个文件)...

//--- 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>()};
}
Run Code Online (Sandbox Code Playgroud)

使用Visual C ++编译器,我得到一个链接器错误(LNK2019)。使用GCC 4.8.4并非如此。将前向声明类SomeInterface更改为struct SomeInterface可使链接器错误消失。我一直以为应该可以互换使用类/结构?SomeInterfaceUser的接口不应取决于SomeInterface是定义为类还是struct,不是吗?

这是Visual C ++错误吗?我找不到任何与此有关的东西。我怀疑将struct用作模板参数这一事实与它有关。

感谢您的帮助。

cbu*_*art 7

我刚刚在 VC++ 2010 和 VC++ 2017 中都遇到了同样的问题,经过一些测试,我发现问题在于编译器在内部为结构和类提供的符号名称。

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

主程序

#include "bar.h"
struct Foo {};

int main() {
  Foo foo;
  bar(&foo);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

酒吧.h

class Foo;
void bar(Foo* f);
Run Code Online (Sandbox Code Playgroud)

bar.cpp

#include "bar.h"

void bar(Foo* foo) {}
Run Code Online (Sandbox Code Playgroud)

编译项目时出现以下错误和警告:

警告 C4099:“Foo”:首先使用“class”看到的类型名称现在使用“struct”看到

见'Foo'的声明

错误 LNK2019:未解析的外部符号“void __cdecl bar(struct Foo *)”(?bar@@YAXPAUFoo@@@Z) 在函数 _main 中引用

致命错误 LNK1120:1 个未解析的外部

现在,我换了struct,并class声明,所以main.cppbar.h现在:

主程序

#include "bar.h"
class Foo {};

int main() {
  Foo foo;
  bar(&foo);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

酒吧.h

struct Foo;
void bar(Foo* f);
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,错误仍然弹出:

错误 LNK2019:函数 _main 中引用了未解析的外部符号“void __cdecl bar(class Foo *)”(?bar@@YAXPAVFoo@@@Z)

但是,这是有趣的部分,请参阅main()每种情况下预期函数的符号(在 中使用的符号)不同:

  • ?bar@@YAXPAUFoo@@@Z(当参数为 a 时struct

  • ?bar@@YAXPAVFoo@@@Z(当参数为 a 时class


结论

如果类型是结构体或类,编译器给出的名称略有不同。

然后链接器找不到正确的定义,因为它正在寻找不同的bar.cpp定义:使用前向声明定义一个,但目前它在main.cpp实际声明中被调用,因此符号表中给出了不同的函数名称.

  • 刚碰到同样的问题,花了我 2~3 个小时才找出原因。从未想过 MSVC(VS 2017) 会因此而发出链接器错误。 (2认同)