LNK4217对从抽象DLL接口类派生的类的警告

时间:2019-02-22 15:10:45

标签: c++

在编译两个类时,我收到LNK4217警告:一个正在定义抽象接口和静态工厂方法,该方法将返回实现此接口的对象。此类通过__declspec(dllexport)导出。另一个类实现接口。这是一个还原警告的简化示例:

PublicAPI.h

#pragma once

#include <memory>

#ifdef PublicAPI_Exports
#define API_EXP __declspec (dllexport)
#else
#define API_EXP __declspec (dllimport)
#endif

class API_EXP PublicAPI
{
public:
  virtual ~PublicAPI();

  static std::shared_ptr<PublicAPI> init(const char *selection);

  virtual int compute() = 0;

protected:
  PublicAPI();
};

PublicAPI.cpp

#include "PublicAPI.h"
#include "../PrivateAPI/PrivateAPI.h"

PublicAPI::PublicAPI() {}

PublicAPI::~PublicAPI() {}

std::shared_ptr<PublicAPI> PublicAPI::init(const char *selection)
{
  return std::make_shared<PrivateAPI>(selection);
}

PrivateAPI.h

#pragma once

#include "../PublicAPI/PublicAPI.h"
#include <memory>
#include <string>

class PrivateAPI : public PublicAPI
{
public:
  PrivateAPI(std::string selection);
  virtual ~PrivateAPI();

  virtual int compute();

private:
  PrivateAPI();
  // should have more private members here, avoided to shorten the example
};

PrivateAPI.cpp

#include "PrivateAPI.h"

PrivateAPI::PrivateAPI() {}

PrivateAPI::PrivateAPI(std::string selection)
{
  // init members based on selection
}

PrivateAPI::~PrivateAPI() {}

int PrivateAPI::compute()
{
  return 42;
}

PrivateAPI编译成静态库,PublicAPI编译成DLL,并链接到PrivateAPIPublicAPI_ExportsPublicAPI项目中定义。

我得到的警告是:

3>PrivateAPI.lib(PrivateAPI.obj) : warning LNK4217: locally defined symbol ??1PublicAPI@@UEAA@XZ (public: virtual __cdecl PublicAPI::~PublicAPI(void)) imported in function "public: virtual __cdecl PrivateAPI::~PrivateAPI(void)" (??1PrivateAPI@@UEAA@XZ)
3>PrivateAPI.lib(PrivateAPI.obj) : warning LNK4217: locally defined symbol ??0PublicAPI@@IEAA@XZ (protected: __cdecl PublicAPI::PublicAPI(void)) imported in function "private: __cdecl PrivateAPI::PrivateAPI(void)" (??0PrivateAPI@@AEAA@XZ)

我已经阅读了Microsoft Docs和StackOverflow上有关此链接器警告的信息,但是在这里我仍然不明白到底是什么错误,或者如何正确修复它:/

1 个答案:

答案 0 :(得分:0)

我能够找出两种解决方案:

解决方案1 ​​(由@HansPassant和imho提供,更好/更通用的解决方案)

不仅需要为PublicAPI_Exports项目,还需要为PrivateAPI项目定义PublicAPI

我对原因的理解:PrivateAPI类是从PublicAPI继承的,因此它也包含PublicAPI.hPrivateAPI还在“继承” PublicAPI中的dllimport / dllexport定义。但是,PrivateAPI被独立编译为静态库,并且以后仅由PublicAPI链接。因此,当在没有定义{em> PrivateAPI的情况下 编译PublicAPI_Exports时,PrivateAPI类将被定义为dllimport(通过PublicAPI.h)。在PublicAPI项目的构建过程中,定义了 PublicAPI_Exports并将其链接到PrivateAPI静态库时,这些定义不匹配并引起此警告。因此,必须同时为PublicAPI_ExportsPublicAPI项目定义PrivateAPI

解决方案2 (对于我的示例)

似乎我也只能dllexport静态init函数,该函数创建一个满足PublicAPI接口的对象。这需要如下更改PublicAPI.h

#pragma once

#include <memory>

#ifdef PublicAPI_Exports
#define API_EXP __declspec (dllexport)
#else
#define API_EXP __declspec (dllimport)
#endif

class PublicAPI
{
public:
  virtual ~PublicAPI();

  API_EXP static std::shared_ptr<PublicAPI> init(const char *selection);

  virtual int compute() = 0;

protected:
  PublicAPI();
};

这有效,因为在PrivateAPI中没有再次声明静态函数。由init返回的对象在包含并链接compute的客户端中似乎可以正常工作(即可以访问PublicAPI函数)。