编译器警告(级别 2)C4251

“type”:“type1”类需要有 dll 接口才能供“type2”类的客户端使用

备注

如果类使用 __declspec(dllexport)__declspec(dllimport) 进行标记且作为该类的成员或该类某个基类的成员的非静态数据成员的类的类型未使用 __declspec(dllexport)__declspec(dllimport) 进行标记,则会发生此警告。 请参阅示例

为了在导出声明为 __declspec(dllexport) 的类时尽量减少数据损坏的可能性,请确保:

  • 通过从 DLL 导出的函数访问所有静态数据。
  • 类的任何内联方法都不能修改静态数据。
  • 类的任何内联方法都不会使用 CRT 函数或使用静态数据的其他库函数。 有关详细信息,请参阅跨 DLL 边界传递 CRT 对象的潜在错误
  • 类的任何方法(无论是否内联)都不能使用 EXE 和 DLL 中的实例化具有静态数据差异的类型。

可以通过以下方法避免从 DLL 导出类时出现问题:

  • 定义类使其具有虚拟函数。
  • 定义虚拟析构函数。
  • 定义用于实例化和删除该类型的实例的函数。

如果类派生自 C++ 标准库中的类型,而你正在编译调试版本 (/MTd),并且编译器错误消息引用 _Container_base,则可以忽略 C4251。

应慎重将 __declspec(dllexport)__declspec(dllimport) 添加到类中,因为这大概率会成为一种不正确的选择,它会增加更改实现细节的难度,进而使维护变得更加困难。

示例

// C4251.cpp
// Compile with /std:c++20 /EHsc /W2 /c C4251.cpp
#include <vector>
 
class __declspec(dllexport) X
{
public:
    X();
    ~X();
 
    void do_something();
 
private:
    void do_something_else();
    std::vector<int> data; // warning c4251
};

若要修复此警告,请勿使用 __declspec(dllexport)__declspec(dllimport) 标记类。 只需标记客户端直接使用的方法。 例如:

// C4251_fixed.cpp
// Compile with /std:c++20 /EHsc /W2 /c C4251-fixed.cpp
#include <vector>
 
class X
{
public:
    __declspec(dllexport) X();
    __declspec(dllexport) ~X();
 
    __declspec(dllexport) void do_something();
 
private:
    void do_something_else();
    std::vector<int> data;
};