C++ LNK4217对从抽象DLL接口类派生的类发出警告
编译两个类时,我收到LNK4217警告:一个是定义抽象接口和静态工厂方法,该方法将返回实现该接口的对象。此类通过C++ LNK4217对从抽象DLL接口类派生的类发出警告,c++,C++,编译两个类时,我收到LNK4217警告:一个是定义抽象接口和静态工厂方法,该方法将返回实现该接口的对象。此类通过\uuu declspec(dllexport)导出。另一个类实现该接口。下面是一个复制警告的简化示例: PublicAPI.h #pragma once #include <memory> #ifdef PublicAPI_Exports #define API_EXP __declspec (dllexport) #else #define API_EXP __de
\uuu 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();
};
PrivateAPI
被编译成一个静态库,PublicAPI
被编译成一个DLL,并链接到PrivateAPI
<代码>PublicAPI_导出在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)
我通读了与此链接器警告相关的和StackOverflow,但我仍然不知道这里到底出了什么问题,也不知道如何正确修复它://我找到了两种解决方案: 解决方案1(由@HansPassant和imho提供更好/更通用的解决方案)
PublicAPI\u导出
也需要为PrivateAPI
项目定义,而不仅仅是为PublicAPI
项目定义
我对原因的理解是:PrivateAPI
类继承自PublicAPI
,因此它还包括PublicAPI.h
。PrivateAPI
还“继承”了PublicAPI
中的dlliport/dllexport定义。但是,PrivateAPI
被独立编译成一个静态库,之后仅由PublicAPI
链接。因此,当编译PrivateAPI
时,未定义PublicAPI\u Exports
,则PrivateAPI
类将被定义为dllimport
(通过PublicAPI.h
)。当PublicAPI
项目在定义了PublicAPI\u Exports
并链接到PrivateAPI
静态库的情况下生成时,这些定义不匹配并导致此警告。因此,有必要为PublicAPI
和PrivateAPI
项目定义PublicAPI\u Exports
解决方案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();
};
#pragma一次
#包括
#ifdef PublicAPI_导出
#定义API EXP declspec(dllexport)
#否则
#定义API EXP declspec(dllimport)
#恩迪夫
公共API类
{
公众:
virtual~PublicAPI();
API_EXP static std::shared_ptr init(const char*selection);
虚拟int compute()=0;
受保护的:
PublicAPI();
};
这是可行的,因为在
PrivateAPI
中不会再次声明静态函数。init
返回的对象在包含并链接PublicAPI
的客户机中似乎工作正常(即compute
函数可访问)。您忘记在构建DLL的项目中定义PublicAPI\u Exports宏。因此链接器会看到两个定义,一个是dllimport,另一个在.cpp文件中。这违反了ODR。右键单击项目>属性>C/C++>预处理器>“预处理器定义”设置。添加PublicAPI_导出。@HansPassant PublicAPI_导出是在PublicAPI项目中定义的(如上所述)-我只是仔细检查了一下。链接器不是这么说的。确保为所有配置和所有平台定义了它。请记住,对于您链接的静态库,它很容易被忽略。好的,在PrivateAPI项目中另外定义PublicAPI_Exports宏可以解决此警告。为了确保我正确理解了背后的原因:PrivateAPI包含PublicAPI头来定义从PublicAPI继承的类。因此,在将PrivateAPI编译成静态库时,我们必须确保在PublicAPI头中定义了dllexport,因为后来PublicAPI(也定义了dllexport)链接到PrivateAPI静态库,导出定义必须匹配!?
#include "PrivateAPI.h"
PrivateAPI::PrivateAPI() {}
PrivateAPI::PrivateAPI(std::string selection)
{
// init members based on selection
}
PrivateAPI::~PrivateAPI() {}
int PrivateAPI::compute()
{
return 42;
}
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)
#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();
};