静态库与动态链接库

  • 静态库一般是.lib格式,而动态链接库一般是.dll格式
    • 静态库 只能 静态链接,此时静态库的内容将被完全嵌入到程序文件中
    • 动态链接库可以静态链接,此时程序在启动时就需要依赖和加载对应的.dll文件(没有dll程序打不开)
    • 动态链接库可以动态链接,此时程序在执行导入函数后才需要依赖和加载对应的.dll文件(没有dll程序也能打开但功能受限)

静态库

  • 设置编译后的程序格式:需要在项目设置里将“配置类型”改为“静态库(.lib)”
    • 即对应的vcxproj文件内容:
1
2
3
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
  • 定义函数和类时无需任何额外的操作
    • 实际上就是在写“库”,与在主程序同文件夹下新建xxx.hxxx.cc并无使用上的区别
    • 优势:使代码可以跨项目复用
  • 以定义一个类为例,静态库内的代码形式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 主程序和库共用的头文件,include/example.h
#pragma once

// 接口
class IExample
{
public:
IExample() = default;
virtual ~IExample() = default;

virtual int get_A() = 0;
virtual std::string get_B() = 0;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 库的头文件,static_lib.h
#pragma once
#include "include/example.h"

// 接口实现为类
class ExampleClass: public IExample
{
int m_iA;
std::string m_szB;

public:
ExampleClass(int in_iA, std::string in_szB): m_iA(in_iA), m_szB(in_szB) { };
~ExampleClass() override = default;

int get_A() override;
std::string get_B() override;
};

// 库内函数
IExample* createObject(int in_iA, std::string in_szB);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 库的代码,static_lib.cc
#include "lib.h"

int ExampleClass::get_A()
{
return this->m_iA;
}

std::string ExampleClass::get_B()
{
return this->m_szB;
}

// 函数示例:创建一个对象并返回其指针;对象放在堆上,手动管理其作用域
IExample* createObject(int in_iA, std::string in_szB)
{
ExampleClass *newObj = new ExampleClass(in_iA, in_szB);
return newObj;
}

//全局变量示例
int TestC = 100;

使用静态库的主程序

  • 需要在链接时指定链接库文件
    • 使用#pragma#pragma comment(lib, "static_lib.lib")
    • 编辑项目设置并在其中添加文件:项目设置 -> 配置属性 -> 链接器 -> 输入 -> 附加依赖项 -> 编辑 -> (添加链接库的文件位置)
      • 即对应的vcxproj文件内容:
1
2
3
<Link>
<AdditionalDependencies>static_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
  • 需要在主程序中使用extern关键字声明静态库中的函数/全局变量
  • 随后调用该函数/变量即可
  • 主程序的代码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 引入IExample的定义
#include "include/example.h"
#include <iostream>

// 引入库中的全局变量
extern int TestC;
// 引入库内的函数
extern IExample* createObject(int in_iA, std::string in_szB);

// 主函数内就能使用类
int main()
{
std::cout << TestC << std::endl;
IExample *TestD = createObject(100, "Hello, World!");

return 0;
}
  • 以上代码同样演示了一种 主程序和库共享接口定义时传递对象的方法:
    • 主程序和库同时有接口的定义
    • 库内将接口实现为类,可对类进行各种操作,并定义一个初始化函数:在堆上实例化子类,并返回接口的指针类型
    • 主程序调用初始化函数,得到指针,根据接口的定义进行各种操作
  • 示例如下:
1
2
接口定义IExample -> 静态库引入 -> 实例化为CExample(可以添加新成员变量和成员方法) -> 定义createObject,返回IExample*;
接口定义IExample -> 主程序引入 -> 设置使用静态库 -> 引入createObject -> 获得IExample*类型变量(CExample中新加的成员变量和成员方法不可用);

动态链接库

评论