在编译两个类时,我收到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,并链接到PrivateAPI
。 PublicAPI_Exports
在PublicAPI
项目中定义。
我得到的警告是:
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上有关此链接器警告的信息,但是在这里我仍然不明白到底是什么错误,或者如何正确修复它:/
答案 0 :(得分:0)
我能够找出两种解决方案:
解决方案1 (由@HansPassant和imho提供,更好/更通用的解决方案)
不仅需要为PublicAPI_Exports
项目,还需要为PrivateAPI
项目定义PublicAPI
。
我对原因的理解:PrivateAPI
类是从PublicAPI
继承的,因此它也包含PublicAPI.h
。 PrivateAPI
还在“继承” PublicAPI
中的dllimport / dllexport定义。但是,PrivateAPI
被独立编译为静态库,并且以后仅由PublicAPI
链接。因此,当在没有定义{em> PrivateAPI
的情况下 编译PublicAPI_Exports
时,PrivateAPI
类将被定义为dllimport
(通过PublicAPI.h
)。在PublicAPI
项目的构建过程中,定义了 PublicAPI_Exports
并将其链接到PrivateAPI
静态库时,这些定义不匹配并引起此警告。因此,必须同时为PublicAPI_Exports
和PublicAPI
项目定义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
函数)。