動态連結庫為子產品化應用程式提供了一種方式,使得更新和重用程式更加友善,當幾個應用程式在同一時間使用相同的函數時,它也幫助減少記憶體消耗,這是因為雖然每個應用程式有獨立的資料拷貝,但是它們的代碼是共享的。
C++ 庫會涉及到三個東西: .h .lib .dll檔案。
庫的使用方式有三種:
1>. .h + .lib
2>. .dll
3>. .h + .lib + .dll
第三種方式是最常見的,第一種次之,第二種較少用。
(下面執行個體使用vs2013)
1>. .h + .lib
lib中存放了函數名及具體的函數實作代碼,編譯器連結時,連結lib檔案到exe可執行程式中。
a. 建立庫lib項目exampleLibFile: 建立項目,選擇-->Win32 控制台應用程式,應用類型選擇-->靜态庫 , 附加選項: 選擇--> 空項目,取消預編譯頭和安全開發生命周期檢查,(選擇控制台應用程式在項目,在項目屬性修改下 --正常--配置類型--中選擇--靜态庫(.lib) 也可以建立lib項目)。

b. 建立庫lib代碼:
添加 .hpp 和 .cpp 檔案( myLib.hpp myLib.cpp )
//.h 頭檔案
void go();
int add(int a, int b);
// cpp 檔案
#include <stdio.h>
#include <windows.h>
void go() {
MessageBox(NULL, "我的來自lib的對話框", "Hello Lib", MB_OK);
}
int add(int a, int b) {
return a + b;
}
c. 編譯生成 exampleLibFile.lib 檔案。
d. 調用者項目中使用 myLib.hpp 和 exampleLibFile.lib 檔案。
#include <stdio.h>
#include "myLib.hpp"
#pragma comment(lib,"../Debug/exampleLibFile.lib")
int main(void) {
go();
printf("來自lib的Add函數:%d\n", add(1, 2));
system("pause");
return 0;
}
2>. dll (使用 winapi調用)
dll中存放了函數名及具體的函數實作代碼,運作時exe可執行程式通過winapi加載dll庫檔案。
a. 建立庫dll項目exampleDllFile: 建立項目,選擇-->Win32 控制台應用程式,應用類型選擇-->靜态庫 , 附加選項: 選擇--> 空項目,取消預編譯頭和安全開發生命周期檢查,(選擇控制台應用程式在項目,在項目屬性修改下 --正常--配置類型--中選擇--靜态庫(.lib) 也可以建立lib項目)。
b. 建立庫dll代碼:
添加 .hpp 和 .cpp 檔案( classDll.hpp classDll.cpp 測試導出類, myDll.c測試導出函數)
//myDll.c
#include <stdio.h>
#include <windows.h>
//如果需要生成可供外部程式調用的函數,必須用dllexport
_declspec(dllexport) void go() {
MessageBox(NULL, "我是來自dll", "hello Dll", MB_OK);
}
//檔案名為c 和 cpp, 生成的函數名字不同,因為C++有函數名重載機制,C沒有
//cpp file
//void go(int a) {
//
//}
//
//void go(int a, double b) {
//
//}
//classDll.hpp檔案
//導出類和導出函數一樣 需要在前面加 __declspec(dllexport) 這是windows特有的
//庫中定義的類和函數 會被兩個項目使用 即原來dll項目和調用者項目
//是以要通過宏 預處理指令來實作庫中定義的類和函數能被兩個項目使用
//這裡的.hpp 頭檔案會被分成兩個檔案 一個嵌入編譯dll庫檔案中 另一個以.h檔案方式供調用者使用
//在建立庫項目時vs 編輯器會預設為庫項目添加預處理宏: EXAMPLEDLLFILE_EXPORTS, (項目名_EXPORTS),這宏也可以手動添加。
//根據這個預處理宏來差別這個頭檔案是在dll庫中使用還是在調用者項目中使用
#ifdef _WIN32 // WIN32知識 32位程式 _WIN64 _WIN32不區分32位和64
#ifdef EXAMPLEDLLFILE_EXPORTS //代表是庫檔案 dllexport: 導出
#define DLL_API __declspec(dllexport)
#else //代表調用者檔案 dllimport: 導入
#define DLL_API __declspec(dllimport)
#endif
#else //linux 為空
#define DLL_API
#endif
class DLL_API ClassDll {
public:
ClassDll();
~ClassDll();
static int count;
};
// classDll.cpp檔案
#include <iostream>
#include "classDll.hpp"
using namespace std;
int ClassDll::count = 0;
ClassDll::ClassDll() {
cout << "ClassDll Create" << endl;
}
ClassDll::~ClassDll() {
}
c. 編譯生成 exampleDllFile.lib exampleDllFile.dll檔案。
d. 調用者項目中使用 exampleDllFile.dll 檔案。
//main.cpp
#include <stdio.h>
#include <windows.h>
//dll windows api調用方式
int main(void) {
HMODULE myDll = LoadLibrary("exampleDllFile1.dll");
if(NULL != myDll) {
GetProcAddress(myDll, "go")();
}
else {
printf("沒有找到dll");
}
system("pause");
}
3>. .h + .lib + .dll
調用庫的時候,要有兩個檔案 lib 和 dll, lib 中記錄函數名及函數名對應的位址,dll中記錄函數的實作代碼。
a. 建立庫dll項目exampleDllFile: 同 2>. dll (使用 winapi調用) 建立dll項目一樣。
b. 建立庫dll代碼: 同 2>. dll (使用 winapi調用)建立庫dll代碼一樣。
c. 編譯生成 exampleDllFile.lib exampleDllFile.dll檔案。(注意這裡的lib檔案雖然和第一種lib庫檔案字尾名相同,但包含的内容格式不一樣,這地方lib隻有函數名及對應位址, 檔案往往就幾k大小)
d. 調用者項目中使用 classDll.hpp exampleDllFile.lib exampleDllFile.dll 檔案。
#include <iostream>
#include <windows.h>
#include "classDll.hpp"
using namespace std;
int main(int argc, char *argv[]) {
ClassDll cl;
cl.count++;
cout << "count = " << cl.count << endl;
getchar();
return 0;
}
在同一個解決方案中建立庫和調用程式時,最好設定項目依賴關系 友善開發:
如: 設定項目b依賴項目a, 那麼當編譯項目b時, 要確定項目a是最新的,如果不是将先編譯項目a。