平常編程中,常有一些函數不須要進行編譯或者能夠在多個文件中使用(如數據庫輸入/輸 出操做或屏幕控制等標準任務函數)。能夠事先對這些函數進行編譯,而後將它們放置在一些特殊的目標代碼文件中,這些目標代碼文件就稱爲庫。庫文件中的函數 能夠經過鏈接程序與應用程序進行連接,這樣就沒必要在每次開發程序時都對這些通用的函數進行編譯了。linux
動態庫是一種在已經編譯完畢的程序開始啓動運行時,才被加載來調用其中函數的庫。其加載方式與靜態庫大相徑庭。ios
Linux下,動態庫一般以.so(shareobject)結尾。(一般/lib和/usr/lib等目錄下存在大量系統提供的以.so結尾的動態庫文件)c++
Windows下,動態庫常以.dll結尾。(一般C:\windows\System32等目錄下存在大量系統提供的以.dll結尾的動態庫文件)算法
靜態庫是指編譯鏈接時,把庫文件的代碼所有加入到可執行文件中,因此生成的文件較大,但運行時,就再也不須要庫文件了。即,程序與靜態庫編譯連接後,即便刪除靜態庫文件,程序也可正常執行。數據庫
動態庫正好相反,在編譯連接時,沒有把庫文件的代碼加入到可執行文件中,因此生成的文件較小,但運行時,仍須要加載庫文件。即,程序只在執行啓動時才加載動態庫,若是刪除動態庫文件,程序將會由於沒法讀取動態庫而產生異常。編程
備註:如下linux實例說明都是在RedHat 5.1系統+ gcc版本 4.1.2 20080704 (Red Hat 4.1.2-46)上實現。windows
可以使用gcc或者g++編譯器生成動態庫文件(此處以g++編譯器爲例)函數
g++ -shared -fPIC -c XXX.cpp工具
g++ -shared -fPIC -o XXX.so XXX.oui
動態庫的調用關係能夠在須要調用動態庫的程序編譯時,經過g++的-L和-l命令來指定。例如:程序test啓動時須要加載目錄/root/src/lib中的libtest_so1.so動態庫,編譯命令可照以下編寫執行:
g++ -g -o test test.cpp –L/root/src/lib –ltest_so1
(此處,咱們重點講解動態庫的動態調用的方法,關於靜態的經過g++編譯命令調用的方式不做詳細講解,具體相關內容可上網查詢)
Linux下,提供專門的一組API用於完成打開動態庫,查找符號,處理出錯,關閉動態庫等功能。
下面對這些接口函數逐一介紹(調用這些接口時,需引用頭文件#include<dlfcn.h>):
1) dlopen
函數原型:void *dlopen(const char *libname,int flag);
功能描述:dlopen必須在dlerror,dlsym和dlclose以前調用,表示要將庫裝載到內存,準備使用。若是要裝載的庫依賴於其它庫,必須首先裝載依賴庫。若是dlopen操做失敗,返回NULL值;若是庫已經被裝載過,則dlopen會返回一樣的句柄。
參數中的libname通常是庫的全路徑,這樣dlopen會直接裝載該文件;若是隻是指定了庫名稱,在dlopen會按照下面的機制去搜尋:
a.根據環境變量LD_LIBRARY_PATH查找
b.根據/etc/ld.so.cache查找
c.查找依次在/lib和/usr/lib目錄查找。
flag參數表示處理未定義函數的方式,可使用RTLD_LAZY或RTLD_NOW。RTLD_LAZY表示暫時不去處理未定義函數,先把庫裝載到內存,等用到沒定義的函數再說;RTLD_NOW表示立刻檢查是否存在未定義的函數,若存在,則dlopen以失敗了結。
2) dlerror
函數原型:char *dlerror(void);
功能描述:dlerror能夠得到最近一次dlopen,dlsym或dlclose操做的錯誤信息,返回NULL表示無錯誤。dlerror在返回錯誤信息的同時,也會清除錯誤信息。
3) dlsym
函數原型:void *dlsym(void *handle,const char *symbol);
功能描述:在dlopen以後,庫被裝載到內存。dlsym能夠得到指定函數(symbol)在內存中的位置(指針)。若是找不到指定函數,則dlsym會返回NULL值。但判斷函數是否存在最好的方法是使用dlerror函數,
4) dlclose
函數原型:int dlclose(void *);
功能描述:將已經裝載的庫句柄減一,若是句柄減至零,則該庫會被卸載。若是存在析構函數,則在dlclose以後,析構函數會被調用。
此處以源碼實例說明。各源碼文件關係以下:
test_so1.h和test_so1.cpp生成test_so1.so動態庫。
test_so2.h和test_so2.cpp生成test_so2.so動態庫。
test_dl.cpp生成test_dl可執行程序,test_dl經過dlopen系列等API函數,並使用函數指針以到達動態調用不一樣so庫中test函數的目的。
////////////////////////////////test_so1.h//////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
extern "C" {
int test(void);
}
////////////////////////////////ttest_so1.cpp//////////////////////////////////////////////////////
#include "test_so1.h"
int test(void)
{
printf("USING TEST_SO1.SO NOW!\n");//注意此處與test_so2.cpp中的
//test函數的不一樣
return 1;
}
//////////////////////////////// test_so2.h//////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
extern "C" {
int test(void);
}
////////////////////////////////ttest_so2.cpp//////////////////////////////////////////////////////
#include "test_so2.h"
int test(void)
{
printf("USING TEST_SO2.SO NOW!\n");//注意此處與test_so1.cpp中的
//test函數的不一樣
return 1;
}
////////////////////////////////test_dl.cpp//////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv)
{
if(argc!=2)
{
printf("Argument Error! You must enter like this:\n");
printf("./test_dl test_so1.so\n");
exit(1);
}
void *handle;
char *error;
typedef void (*pf_t)(); //聲明函數指針類型
handle = dlopen (argv[1],RTLD_NOW); //打開argv[1]指定的動態庫
if (!handle)
{
fprintf (stderr, "%s\n", dlerror());
exit(1);
}
dlerror();
pf_tpf=(pf_t)dlsym(handle,"test"); //指針pf指向test在當前內存中的地址
if ((error = dlerror()) != NULL)
{
fprintf (stderr, "%s\n", error);
exit(1);
}
pf(); //經過指針pf的調用來調用動態庫中的test函數
dlclose(handle); //關閉調用動態庫句柄
return 0;
}
////////////////////////////////makefile//////////////////////////////////////////////////////
.SUFFIXES: .c .cpp .o
CC=g++ -shared -fPIC
GCC=g++
all:test_so1.so test_so2.so test_dl clean
OBJ1=test_so1.o
OBJ2=test_so2.o
OBJ3=test_dl.o
test_so1.so:$(OBJ1)
$(CC) -o $@ $?
cp $@ /usr/lib
test_so2.so:$(OBJ2)
$(CC) -o $@ $?
cp $@ /usr/lib
test_dl:$(OBJ3)
$(GCC) -o $@ $? -ldl
.cpp.o:
$(CC) -c $*.cpp
.c.o:
$(CC)-c $*.c
clean:
rm -f *.o
上述源程序中,需重點注意兩個問題:
一、test_dl.cpp中,對於動態庫中的test函數調用是經過函數指針來完成的。
二、test_so1.h和test_so2.h中都使用了extern "C"。
在每一個C++程序(或庫、目標文件)中,全部非靜態(non-static)函數在二進制文件中都是以「符號(symbol)」形式出現的。這些符號都是惟一的字符串,從而把各個函數在程序、庫、目標文件中區分開來。
在C中,符號名正是函數名:strcpy函數的符號名就是「strcpy」。這多是由於兩個非靜態函數的名字必定各不相同的緣故。
而C++容許重載(不一樣的函數有相同的名字但不一樣的參數),而且有不少C所沒有的特性 ──好比類、成員函數、異常說明──幾乎不可能直接用函數名做符號名。爲了解決這個問題,C++採用了所謂的namemangling。它把函數名和一些 信息(如參數數量和大小)雜糅在一塊兒,改形成奇形怪狀,只有編譯器才懂的符號名。例如,被mangle後的foo可能看起來像foo@4%6^,或者,符 號名裏頭甚至不包括「foo」。
其中一個問題是,C++標準(目前是[ISO14882])並無定義名字必須如何被 mangle,因此每一個編譯器都按本身的方式來進行namemangling。有些編譯器甚至在不一樣版本間更換mangling算法(尤爲是g++2.x 和3.x)。即便您搞清楚了您的編譯器到底怎麼進行mangling的,從而能夠用dlsym調用函數了,但可能僅僅限於您手頭的這個編譯器而已,而沒法 在下一版編譯器下工做。
用 extern "C"聲明的函數將使用函數名做符號名,就像C函數同樣。所以,只有非成員函數才能被聲明爲extern"C",而且不能被重載。儘管限制多 多,extern"C"函數仍是很是有用,由於它們能夠象C函數同樣被dlopen動態加載。冠以extern"C"限定符後,並不意味着函數中沒法使用 C++代碼了,相反,它仍然是一個徹底的C++函數,可使用任何C++特性和各類類型的參數。
執行makefile正常編譯後,可生成test_so1.so、test_so2.so動態庫以及test_dl執行程序。可執行test_dl,顯示結果以下:
[root@localhost so_src]# ./test_dl test_so1.so
USING TEST_SO1.SO NOW!
[root@localhost so_src]# ./test_dl test_so2.so
USING TEST_SO2.SO NOW!
[root@localhost so_src]# ./test_dl
Argument Error! You must enter like this:
./test_dl test_so1.so
備註:若是咱們去掉test_so1.h和test_so2.h中的extern"C",從新編譯執行後將可能會出現什麼狀況?有興趣的朋友能夠試下:
[root@localhost so_src]# ./test_dl test_so1.so
/usr/lib/test_so1.so: undefined symbol: test
[root@localhost so_src]# ./test_dl test_so2.so
/usr/lib/test_so2.so: undefined symbol: test
加載類有點困難,由於咱們須要類的一個實例,而不只僅是一個函數指針。咱們沒法經過new來建立類的實例,由於類是在動態庫中定義的而不是在可執行程序中定義的,何況有時候咱們連動態庫中具體的類的名字都不知道。
解決方案是:利用多態性!咱們在可執行文件中定義一個帶虛成員函數的接口基類,而在模 塊中定義派生實現類。一般來講,接口類是抽象的(若是一個類含有虛函數,那它就是抽象的)。由於動態加載類每每用於實現插件,這意味着必須提供一個清晰定 義的接口──咱們將定義一個接口類和派生實現類。
接下來,在模塊中,咱們會定義兩個附加的類工廠函數(class factoryfunctions)(或稱對象工廠函數)。其中一個函數建立一個類實例,並返回其指針;另外一個函數則用以銷燬該指針。這兩個函數都以extern"C"來限定修飾。
實例以下:
test_base.hpp中定義一個含有純虛函數virtual void display() const = 0的基類。
test_1.cpp中定義繼承類test1,並實現虛函數virtual void display()const的定義,並實現一個建立類函數和一個銷燬類指針函數。
test_2.cpp中定義繼承類test2,並實現虛函數virtual void display()const的定義,並實現一個建立類函數和一個銷燬類指針函數。
main.cpp中實現動態的調用不一樣庫中的display()方法。
////////////////////////////////test_base.hpp//////////////////////////////////////////////////////
#ifndef TEST_BASE_HPP
#define TEST_BASE_HPP
#include <iostream>
using namespace std;
class test_base {
public:
test_base(){}
virtual~test_base() {}
voidcall_base() {
cout << "call base"<< endl;
}
virtualvoid display() const = 0 ;
};
// the types of the class factories
typedef test_base* create_t();
typedef void destroy_t(test_base*);
#endif
////////////////////////////////test1.cpp//////////////////////////////////////////////////////
#include "test_base.hpp"
class test1 : public test_base {
public:
virtualvoid display() const {
cout << "Running in test1.so Now"<< endl;
}
};
// the class factories
extern "C" test_base* create() {
returnnew test1;
}
extern "C" void destroy(test_base* p) {
deletep;
}
////////////////////////////////test1.cpp//////////////////////////////////////////////////////
#include "test_base.hpp"
class test2 : public test_base {
public:
virtualvoid display() const {
cout << "Running in test2.so Now"<< endl;
}
};
// the class factories
extern "C" test_base* create() {
returnnew test2;
}
extern "C" void destroy(test_base* p) {
deletep;
}
////////////////////////////////main.cpp//////////////////////////////////////////////////////
#include "test_base.hpp"
#include <iostream>
#include <dlfcn.h>
int main(int argc , char** argv) {
// loadthe test library
if(argc!=2)
{
cout << "Argument Error! You mustenter like this: " << '\n';
cout << "./a.out test_1.so "<< '\n';
return 1;
}
void*test_index = dlopen(argv[1], RTLD_NOW);
if(!test_index) {
cerr << "Cannot load library: "<< dlerror()<< '\n';
return 1;
}
// reseterrors
dlerror();
// loadthe symbols
create_t*create_test = (create_t*) dlsym(test_index, "create");
constchar* dlsym_error = dlerror();
if(dlsym_error) {
cerr << "Cannot load symbol create: "<< dlsym_error<< '\n';
return 1;
}
destroy_t* destroy_test = (destroy_t*) dlsym(test_index,"destroy");
dlsym_error = dlerror();
if(dlsym_error) {
cerr<< "Cannot load symbol destroy: "<< dlsym_error<< '\n';
return 1;
}
// createan instance of the class
test_base* c_test = create_test();
// usethe class
c_test->display();
destroy_test(c_test);
// unloadthe test library
dlclose(test_index);
}
////////////////////////////////makefile//////////////////////////////////////////////////////
.SUFFIXES: .c .cpp .o
CC=g++ -g -shared -fPIC
GCC=g++ -g
all:clear test_1.so a.out test_2.so clean
OBJ1=test_1.o
OBJ2=main.o
OBJ3=test_2.o
clear:
rm -rf *.so a.out b.out
test_1.so:$(OBJ1)
$(CC) -o $@ $?
cp $@ /usr/lib
a.out:$(OBJ2)
$(GCC) -o $@ $? -ldl
test_2.so:$(OBJ3)
$(CC) -o $@ $?
cp $@ /usr/lib
.cpp.o:
$(CC) -c $*.cpp
.c.o:
$(CC) -c $*.c
clean:
rm -f *.o
執行makefile正常編譯後,可生成test_1.so、test_2.so動態庫以及a.out執行程序。可執行a.out,顯示結果以下:
[root@localhost c++_so_src]# ./a.out test_1.so
Running in test1.so Now
[root@localhost c++_so_src]# ./a.out test_2.so
Running in test2.so Now
[root@localhost c++_so_src]# ./a.out
Argument Error! You must enter like this:
./a.out test_1.so
備註:如下windows實例說明都是在Win7系統+visual studio2005上實現。
使用visual studio2005工具,建立一個新項目,選擇Win32——Win32控制檯應用程序(此處需選擇名稱及位置)——應用程序類型:DLL+附加選項:空項目,完成以上步驟便可建立一個dll項目。
在項目中的頭文件和源文件、資源文件中新增相應代碼後,經過工具欄中Build(生成)便可生成相應dll文件。dll文件生成的位置一般在該項目位置中的debug目錄下。
1) LoadLibrary
函數原型:HMODUBLE WINAPI LoadLibrary(LPCTSTR lpFileName);
(其中HMODUBLE一般是被載入模塊的線性地址類型;LPCTSTR =const tchar *。)
功能描述:表示要將庫裝載到內存,準備使用。若是要裝載的庫依賴於其它庫,必須首先裝載依賴庫。若是LoadLibrary操做失敗,返回NULL值;若是庫已經被裝載過,則LoadLibrary會返回一樣的句柄。
參數中的lpFileName通常是庫的全路徑,這樣LoadLibrary會直接裝載該文件;若是隻是指定了庫名稱,在LoadLibrary會在當前目錄下查找。
2) GetProcAddress
函數原型:FARPROC WINAPI GetProcAddress (HMODUBLEhModule,LPCTSTR lpProcName);
(其中FARPROC 一般表明函數指針)
功能描述:表示已獲取指向應用程序要調用的每一個導出函數的函數指針。因爲應用程序是經過指針調用 DLL的函數,編譯器不生成外部引用,故無需與導入庫連接。
參數中的hModule是由LoadLibrary加載庫後返回的模塊線性地址句柄;lpProcName是要調用的庫函數名稱。
3) GetProcAddress
函數原型: BOOL WINAPI FreeLibrary(HMODUBLE hModule)
功能描述:使用完 DLL 後調用FreeLibrary卸載動態庫。卸載成功返回true,不然返回false。
使用visual studio2005工具,建立一個新項目,選擇Win32——Win32控制檯應用程序(此處需選擇名稱及位置,假設該處名稱爲dll_load)—— 應用程序類型:控制檯應用程序+附加選項:預編譯頭,完成以上步驟便可建立一個dll_load項目。
建立dll_load項目完畢後,修改項目的字符集屬性,步驟以下:
項目——dll_load屬性(最後一行就是)——配置屬性——常規——字符集,設置 爲「未設置」。項目默認建立的字符集爲「使用UNICODE字符集」。(若是字符集設置爲UNICODE字符集的話,調試程序時沒法自動實現「char *」轉換爲「LPCWSTR」,需使用_T()或其它方法解決)
而後,在該dll_load項目中,繼續添加dll1和dll2項目,添加步驟以下:
文件——添加——新建項目——Win32——Win32控制檯應用程序(此處填寫名稱dll1,位置默認)——應用程序類型:DLL+附加選項:空項目。
完成以上步驟便可在當前dll_deal項目中增長dll1項目。dll2項目也可參照dll1項目的添加便可。
在dll_load、dll1和dll2項目中增長下圖.h和.cpp源程序文件(其中dll_deal中的stdafx.h和stdafx.cpp爲項目建立時默認生成,無需增長)。
各源程序文件代碼以下:
dll1.h/dll1.cpp聲明定義int test()方法,並生成dll1.dll動態庫。
dll2.h/dll2.cpp聲明定義int test()方法,並生成dll2.dll動態庫。
dll_load.cpp中實現調用不一樣動態庫的test()方法。
////////////////////////////////dll_deal.cpp//////////////////////////////////////////////////////
// dll_load.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include<stdio.h>
#include<windows.h>
#include<winuser.h>
#include<tchar.h>
#include<stdlib.h>
typedef int(*lpFun)(); //定義函數指針類型
int main()
{
HINSTANCE hDll; //DLL句柄
lpFun testFun; //函數指針
char *dll_name=(char *)malloc(1024);
printf("Please choose the dll_name(dll1.dll or dll2.dll):\n");
scanf("%s",dll_name);
printf("\n");
hDll = LoadLibrary(dll_name);//加載DLL,須要將DLL放到工程目錄下.
free(dll_name);
if (hDll != NULL)
{
printf("LOAD DLL success\n");
testFun = (lpFun)GetProcAddress(hDll, "test");
if (testFun != NULL)
{
testFun();
}
else
{
printf("the calling is error\n");
}
FreeLibrary(hDll);
}
else
{
printf("Load DLL Error or DLL not exist!\n");
}
return 0;
}
////////////////////////////////dll1.h//////////////////////////////////////////////////////
#ifdef DLL1_API
#else
#define DLL1_API extern "C"_declspec(dllimport) //同.cpp文件中同步
#endif
DLL1_API int test(); //代表函數是從DLL導入,給客戶端使用
////////////////////////////////dll1.cpp//////////////////////////////////////////////////////
#include "dll1.h"
#include<stdlib.h>
#include<stdio.h>
int test()
{
printf("RUNNING in dll1.dll NOW\n");
return 0;
}
////////////////////////////////dll2.h//////////////////////////////////////////////////////
#ifdef DLL2_API
#else
#define DLL2_API extern "C"_declspec(dllimport) //同.cpp文件中同步
#endif
DLL2_API int test(); //代表函數是從DLL導入,給客戶端使用
////////////////////////////////dll2.cpp//////////////////////////////////////////////////////
#include "dll2.h"
#include<stdlib.h>
#include<stdio.h>
int test()
{
printf("RUNNING in dll2.dll NOW\n");
return 0;
}
各源程序中代碼填充完成以後,在dll1項目中完成dll1.dll的生成;在dll2項目中完成dll2.dll的生成;在dll_load項目中進行Debug,結果以下:
輸入dll1.dll或者dll2.dll後,結果以下:
輸入其它無效dll後,結果以下:
使用visual studio2005工具,建立一個新項目,選擇Win32——Win32控制檯應用程序(此處需選擇名稱及位置,假設該處名稱爲dll_deal)—— 應用程序類型:控制檯應用程序+附加選項:預編譯頭,完成以上步驟便可建立一個dll_deal項目。
建立dll_deal項目完畢後,修改項目的字符集屬性,步驟以下:
項目——dll_deal屬性(最後一行就是)——配置屬性——常規——字符集,設置 爲「未設置」。項目默認建立的字符集爲「使用UNICODE字符集」。(若是字符集設置爲UNICODE字符集的話,調試程序時沒法自動實現「char *」轉換爲「LPCWSTR」,需使用_T()或其它方法解決)
而後,在該dll_deal項目中,繼續添加dll1和dll2項目,添加步驟以下:
文件——添加——新建項目——Win32——Win32控制檯應用程序(此處填寫名稱dll1,位置默認)——應用程序類型:DLL+附加選項:空項目。
完成以上步驟便可在當前dll_deal項目中增長dll1項目。dll2項目也可參照dll1項目的添加便可。
在dll_deal、dll1和dll2項目中增長下圖.h和.cpp源程序文件(其中dll_deal中的stdafx.h和stdafx.cpp爲項目建立時默認生成,無需增長)。
各源程序文件代碼以下:
dll_deal.h/dll1.h/dll2.h中定義相同的含有純虛函數virtual void display() const =0的基類。
dll1.cpp中定義繼承類test1,並實現虛函數virtual void display()const的定義,並實現一個建立類函數和一個銷燬類指針函數。
dll2.cpp中定義繼承類test2,並實現虛函數virtual void display()const的定義,並實現一個建立類函數和一個銷燬類指針函數。
dll_deal.cpp中實現調用不一樣動態庫的display()方法。
////////////////////////////////dll_deal.h//////////////////////////////////////////////////////
#ifndef DLL_DEAL_H
#define DLL_DEAL_H
#include<iostream>
using namespace std;
class test_base {
public:
test_base(){}
virtual~test_base() {}
voidcall_base() {
cout << "call base"<< endl;
}
virtual voiddisplay() const = 0 ;
};
// the types of the class factories
typedef test_base* create_t();
typedef void destroy_t(test_base*);
#endif
////////////////////////////////dll_deal.cpp//////////////////////////////////////////////////////
// dll_deal.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <string>
#include<iostream>
#include<windows.h>
#include<winuser.h>
#include "dll_deal.h"
int main()
{
HINSTANCE hDll; //DLL句柄
string dll_name;
cout << "Please choose thedll_name(dll1.dll or dll2.dll):" <<endl;
cin >> dll_name;
cout << endl;
hDll = LoadLibrary(dll_name.c_str());//加載DLL,須要將DLL放到工程目錄下.
if (hDll != NULL)
{
cout << "LOAD DLL success!"<< endl;
// load the symbols
create_t* create_test = (create_t*)GetProcAddress(hDll,"create");
if (create_test == NULL)
{
cout << "Cannot load symbol create:" << endl;
return 1;
}
destroy_t* destroy_test = (destroy_t*)GetProcAddress(hDll,"destroy");
if (destroy_test == NULL)
{
cout << "Cannot load symbol destroy:" << endl;
return 1;
}
// create an instance of the class
test_base* c_test = create_test();
// use the class
c_test->display();
// destroy the class
destroy_test(c_test);
// unload the library
FreeLibrary(hDll);
}
else
{
cout << "Load DLL Error or DLL notexist!" <<endl;
}
return 0;
}
////////////////////////////////dll1.h//////////////////////////////////////////////////////
#ifndef DLL1_H
#define DLL1_H
#include<iostream>
using namespace std;
class test_base {
public:
test_base(){}
virtual~test_base() {}
voidcall_base() {
cout << "call base"<< endl;
}
virtual voiddisplay() const = 0 ;
};
// the types of the class factories
typedef test_base* create_t();
typedef void destroy_t(test_base*);
#endif
////////////////////////////////dll1.cpp//////////////////////////////////////////////////////
#include "dll1.h"
#include <cmath>
class test1 : public test_base {
public:
virtual voiddisplay() const {
cout << "Running in test1.so Now"<< endl;
}
};
// the class factories
extern "C" __declspec(dllexport) test_base* create() {
return newtest1;
}
extern "C" __declspec(dllexport) void destroy(test_base* p) {
deletep;
}
////////////////////////////////dll2.h//////////////////////////////////////////////////////
#ifndef DLL2_H
#define DLL2_H
#include<iostream>
using namespace std;
class test_base {
public:
test_base(){}
virtual~test_base() {}
voidcall_base() {
cout << "call base"<< endl;
}
virtual voiddisplay() const = 0 ;
};
// the types of the class factories
typedef test_base* create_t();
typedef void destroy_t(test_base*);
#endif
////////////////////////////////dll2.cpp//////////////////////////////////////////////////////
#include "dll2.h"
#include <cmath>
class test2 : public test_base {
public:
virtual voiddisplay() const {
cout << "Running in test2.so Now"<< endl;
}
};
// the class factories
extern "C" __declspec(dllexport) test_base* create() {
return newtest2;
}
extern "C" __declspec(dllexport) void destroy(test_base* p) {
deletep;
}
各源程序中代碼填充完成以後,在dll1項目中完成dll1.dll的生成;在dll2項目中完成dll2.dll的生成;在dll_deal項目中進行Debug,結果以下:
輸入dll1.dll或者dll2.dll後,結果以下:
輸入其它無效dll後,結果以下: