Dynamically loaded libraries 動態載入庫 #3 C++ 類別載入
提到 libdl 是 C 函式庫,不包含類別的功能,
而 C++ 物件導向的特性之一多形可以用來達成動態載入類別的功能,
這樣唯一不足的點是,
在要使用動態類別庫的專案中需要加入類別介面標頭,
而不能在讓編譯器完全不知道類別介面的狀況下動態載入。
而 C++ 物件導向的特性之一多形可以用來達成動態載入類別的功能,
這樣唯一不足的點是,
在要使用動態類別庫的專案中需要加入類別介面標頭,
而不能在讓編譯器完全不知道類別介面的狀況下動態載入。
範例類別庫
以下程式為了節省版面沒有使用 #include 防範
HelloWorld.hpp (介面)
class HelloWorld {
public:
HelloWorld() {}
virtual ~HelloWorld() {}
virtual void hello() {}
};
extern "C"{
HelloWorld* create_object();
void destroy_object(HelloWorld* object);
}
會直接實作 HelloWorld 的方法是為了使用上的方便,
不論是不實作或是讓它=0都會有些相對應的問題,
因此我還是將這個 HelloWorld 稱為介面。
不論是不實作或是讓它=0都會有些相對應的問題,
因此我還是將這個 HelloWorld 稱為介面。
create_object 和 destroy_object 兩個函式用於轉發建構子與解構子,
這下就有辦法呼叫其他類別庫中的 HelloWorld 子類別建構子、解構子,
也剛好有 HelloWorld 介面,如此就可以動態載入類別了。
這下就有辦法呼叫其他類別庫中的 HelloWorld 子類別建構子、解構子,
也剛好有 HelloWorld 介面,如此就可以動態載入類別了。
MyHelloWorld.hpp (要被動態載入的類別)
#include "HelloWorld.hpp"
class MyHelloWorld: public HelloWorld {
public:
MyHelloWorld();
virtual ~MyHelloWorld();
virtual void hello();
};
MyHelloWorld.cpp
#include "MyHelloWorld.hpp"
#include <iostream>
/* 轉發建構子*/
HelloWorld* create_object()
{
return new MyHelloWorld;
}
/* 轉發解構子 */
void destroy_object(HelloWorld* object)
{
delete object;
}
MyHelloWorld::MyHelloWorld() {
}
MyHelloWorld::~MyHelloWorld() {
}
void MyHelloWorld::hello(){
std::cout << "Hello World" << std::endl;
}
編譯
$ g++ -c -fPIC MyHelloWorld.cpp
$ g++ -shared -o libmylib.so MyHelloWorld.o
與之前一樣,除了這次檔案換個名字之外,沒什麼需要改變
使用方式
這個專案需要放入剛編譯好的
libmylib.so
和標頭檔 HelloWorld.hpp
main.cpp
#include <dlfcn.h>
#include <iostream>
#include "HelloWorld.hpp"
int main() {
void* handle = dlopen("./libmylib.so", RTLD_LAZY);
HelloWorld* (*create)() = (HelloWorld* (*)())dlsym(handle, "create_object");
void (*destroy)(HelloWorld*)= (void (*)(HelloWorld*))dlsym(handle, "destroy_object");
HelloWorld* myHelloWorld = (HelloWorld*) create();
myHelloWorld->hello();
destroy(myHelloWorld);
dlclose(handle);
return 0;
}
編譯
編譯時要一樣連結 libdl,使用 -ldl
$ g++ main.cpp -ldl
執行
$ ./a.out
結果
Hello World
留言
張貼留言