【问题标题】:Compilation of interface specified in DLLDLL中指定接口的编译
【发布时间】:2014-09-05 00:32:33
【问题描述】:

我在编译从另一个 DLL 的接口派生的类时遇到链接问题。这是代码。我有一个 c++ 接口(抽象类),在 DLL 中指定如下:

// ============================ Source DLL
// header IFace.h"
#ifdef MY_EXPORTS
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif

class MY_API IFace
{
public:
    virtual ~IFace() {};
    virtual bool Foo() = 0;
};

// ============================ My DLL
// header
#ifdef MY_EXPORTS22
#define MY_API22 __declspec(dllexport)
#else
#define MY_API22 __declspec(dllimport)
#endif

#include "IFace.h"

class MY_API22 MyClass_Mock : public IFace
{
// IFace
public:
virtual ~MyClass_Mock() {};
virtual bool Foo() ;
};

// cpp file
bool MyClass_Mock::Foo()
{
    return true;
}

当我编译实现接口 IFace 的 DLL 时,出现链接器错误:

  • 错误 LNK2019:无法解析的外部符号“__declspec(dllimport) 公共:__cdecl IFace::IFace(void)"
  • 错误 LNK2019:未解决 外部符号“__declspec(dllimport) public: __cdecl IFace::IFace(类 IFace const &)"
  • 错误 LNK2019:未解决 外部符号“__declspec(dllimport) public: 类 IFace & __cdecl IFace::operator=(class IFace const &)"
  • 错误 LNK2001:未解决 外部符号“__declspec(dllimport) public: 类 IFace & __cdecl IFace::operator=(class IFace const &)"

当我明确定义(或在 C++11 中删除)复制 ctor 和赋值运算符时,默认 ctor 和 dtor 仍然存在错误。

不想链接源 DLL 的 .lib 文件,因为我想稍后通过 LoadLibrary 动态加载它。如何解决此链接问题?

【问题讨论】:

  • 标准 C++ 不允许您声明没有链接依赖的真正接口。您必须改用非标准的 MSVC++ __interface 关键字。为此添加。
  • 谢谢汉斯。它可以工作,但是对于定义宏 WIN32_LEAN_AND_MEAN 的项目,即使我的小代码 sn-p 没有来自 COM 的任何内容,它也会给出错误“错误 C2504:'IUnknown':基类未定义”。
  • 嗨 Anton K,您找到解决方案了吗?我的意思是避免需要 IFace 的 dll 来编译 MyClass_Mock。谢谢

标签: c++ dll abstract-class


【解决方案1】:

class MY_API IFace 更改为class IFace

如果您指定 MY_API源 DLL 将不会导出 IFace,因为它没有定义。另一方面,我的 DLL 会尝试从 Source DLL 导入 IFace,但由于没有导出的 IFace 定义,它会失败。 p>

如果你删除MY_API,当我的DLL尝试使用IFace时,声明它的头文件就足够了(即IFace.h)。

【讨论】:

    【解决方案2】:

    创建导出接口的 DLL 是一个有问题的领域。

    对于 C++ 类没有标准 ABI,并且不能保证该类(代码兼容)与不同的编译器二进制兼容。

    在 Windows 上有一种半标准形式,其中类与 COM 对象匹配,可以认为是兼容的。

    内存管理

    在 Windows 上,malloc/freenew/delete 在运行时实现。这可能是共享运行时(例如 msvcr120.dll),或编译成二进制文件(.dll、.exe)。如果在一个运行时(静态库)中调用 new 而在另一个运行时调用 delete,则会发生崩溃(免费调用不同的堆)。

    为避免这种情况,请使用静态构造函数来构建您的类,并提供virtual 删除器,或使用引用计数。

    避免实现

    virtual ~IFace() {};
    

    上面的代码创建了在头文件中定义的代码,它被绑定到调用者中。如果此代码与实现不兼容,则可能会调用错误的代码。为确保只调用虚拟接口,需要将接口类限制为可见的功能,而不是实现。

    class IFace {
      public:
        virtual Delete() = 0;
        virtual Method1() = 0;
    ...
    };
    

    IFace * MYAPI 构造函数();

    实施

    class MY_API IFace
    {
      public:
        virtual bool Foo() = 0;
        virtual void Delete() = 0;
    };
    
    
    IFace * MY_API22 MyConstructor()
    
    
    class MY_API22 MyClass_Mock : public IFace
    {
    // IFace
    public:
      virtual void Deletor() { delete this };
      virtual bool Foo() ;
    };
    
    // cpp file
    bool MyClass_Mock::Foo()
    {
        return true;
    }
    IFace * MyConstructor()
    {
         return new MyClass_Mock;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-03
      • 2016-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多