C++编写DLL动态链接库的步骤与实现方法

竹里
竹里
发布时间:2026-10-13| 3人浏览过
原创

C++开发中经常需要将核心逻辑封装为DLL动态链接库供外部调用。正确实现DLL导出机制并选择合适的调用方式(静态或动态),能确保程序稳定运行并避免链接错误。本文将详解如何配置头文件宏、处理名称修饰问题以及通过工厂模式安全获取实例。

结果或目标

成功构建一个C++ DLL项目,并提供客户端程序通过头文件直接调用或通过API函数动态加载该库的能力。

准备条件

  • 开发环境:Visual Studio 或其他支持C++的编译器。
  • 项目结构:建议将DLL源码、头文件与客户端调用代码分开管理,注意不同工程间的头文件包含路径。
  • 基础认知:理解C++ Name Mangling(名称修饰)机制及导入/导出关键字的含义。

真实操作顺序

第1步:定义导出的公共接口头文件

目的:创建一个可在DLL内部和客户端之间共享的头文件,自动根据编译上下文切换导出或导入状态。

动作:在头文件中使用预编译宏控制 _declspec 关键字。

#ifdef DLL_TEST_API
#else
#define DLL_TEST_API _declspec(dllimport)
#endif

class DLL_TEST_API CDLLTest
{
public:
    CDLLTest();
    ~CDLLTest();
    int Add(int a, int b);
};

完成判断:当DLL工程定义 DLL_TEST_API 为导出时,该类将被标记为导出;当客户端不包含该定义时,默认为导入。

第2步:实现DLL源文件与导出配置

目的:将类方法实现打包进DLL,并指定导出符号。

动作:在 .cpp 文件中定义导出宏并包含头文件。

#define DLL_TEST_API _declspec(dllexport)
#include "DLLTest.h"

// 后续添加类的具体方法实现...

重要参数:DLL_TEST_API 必须定义为 _declspec(dllexport) 才能在编译DLL时生成导出表。

第3步:处理成员函数单独导出

目的:仅导出特定方法(如工具函数)而非整个类,减少符号污染。

动作:将宏放置在成员函数声明前。若仅导出部分方法,构造函数和析构函数若未标记导出,客户端在链接时会报错“无法解析的外部符号”。

#ifdef DLL_TEST_API
#else
#define DLL_TEST_API _declspec(dllimport)
#endif

class CDLLTest
{
public:
    DLL_TEST_API CDLLTest(); // 需导出以支持静态链接实例化
    DLL_TEST_API ~CDLLTest();
    int DLL_TEST_API Add(int a, int b);
};

排错提示:如果只需要兼容C语言接口,可加上 extern "C" 防止名称修饰变化,但更稳健的方式是使用 .def 模块定义文件明确指定导出名。

第4步:静态方式调用DLL

目的:像使用本地类一样简单调用DLL功能。

入口:客户端工程属性设置或直接代码引入。

  1. 文件部署:将 DLLTest.dll 和 DLLTest.lib 放入客户端目录。
  2. 引入库:在代码中添加 #pragma comment(lib, "DLLTest.lib"),或在Linker输入项中添加 DLLTest.lib。
  3. 调用代码:
#include "DLLTest.h"

void ClientCall()
{
    CDLLTest dllTest;
    dllTest.Add(1, 2);
}

完成判断:编译连接无歧义,运行时能找到对应的dll并执行方法。

第5步:动态方式调用DLL(含虚函数继承设计)

目的:在不依赖.lib的情况下,通过句柄加载DLL,并利用多态机制安全管理对象生命周期。

风险提醒:直接通过 `LoadLibrary` 获取 C++ 类的指针并在外部 `delete` 可能导致内存管理器不一致引发的崩溃,因此必须通过基类指针操作。

5.1 设计纯虚基类接口

目的:提供一个双方都能识别的抽象基类,用于指针转换和资源释放。

动作:新建 DLLTestBase.h,定义纯虚函数和虚析构函数。

class CDLLTestBase
{
public:
    virtual ~CDLLTestBase(){} // 必须为虚析构函数
    virtual int Add(int a, int b) = 0;
};

5.2 修改DLL实现类

动作:让实际类继承自基类。

#include "DLLTestBase.h"

class CDLLTest : public CDLLTestBase
{
public:
    CDLLTest();
    ~CDLLTest();
    int Add(int a, int b); // 实现基类虚函数
};

5.3 暴露全局工厂函数

目的:提供一个入口点让外部获取指向派生类的基类指针。

动作:在DLL源码中添加如下函数,建议使用 .def 文件固化导出名以防C++名字修饰干扰:

// DLL端代码
extern "C" __declspec(dllexport) CDLLTestBase* GetInstance()
{
    return new CDLLTest; // 返回的是派生类指针,赋值给基类指针
}

5.4 客户端动态加载实现

动作:使用 LoadLibrary 和 GetProcAddress。

#include "DLLTestBase.h"
#include <windows.h>

void DynamicClientCall()
{
    // 1. 加载DLL
    HMODULE hMod = LoadLibrary(_T("DLLTest.DLL"));
    if (!hMod) return;

    // 2. 定义函数指针类型并获取地址
    typedef CDLLTestBase* (*pfGetInst)();
    pfGetInst pfnGetInstance = (pfGetInst)GetProcAddress(hMod, "GetInstance");
    
    if (pfnGetInstance)
    {
        // 3. 获取实例
        CDLLTestBase* pInst = pfnGetInstance();
        if (pInst)
        {
            // 4. 使用基类指针调用
            pInst->Add(1, 2);

            // 5. 释放资源
            // 由于CDLLTestBase有虚析构函数,通过基类指针delete会正确触发派生类析构
            delete pInst;
        }
    }
    FreeLibrary(hMod);
}

重要参数:务必使用 FreeLibrary 释放句柄,并在获取对象后使用 delete 清理堆内存,且删除操作必须通过基类指针进行以保证析构函数链的正确性。

完成判断

当客户端程序能够正常调用 Add 方法并返回预期结果,且在退出时没有内存泄漏警告(可通过VS调试器检测),即表示DLL编写与调用流程正确。

简要总结

C++ DLL的核心在于正确处理 __declspec 宏与符号可见性。对于简单的类导出,静态链接最便捷;对于需要解耦或插件化的场景,推荐使用基类指针配合工厂模式的动态加载方案,这不仅能绕过名称修饰问题,还能利用C++的多态特性安全地分配和释放跨边界对象。

以上就是C++编写DLL动态链接库的详细步骤,更多关于C++开发技巧的资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。