kelasku.h
#ifndef __MYCLASS_H__
#define __MYCLASS_H__
class MyClass
{
public:
MyClass();
/* use virtual otherwise linker will try to perform static linkage */
virtual void DoSomething();
private:
int x;
};
#endif
kelasku.cc
#include "myclass.h"
#include <iostream>
using namespace std;
extern "C" MyClass* create_object()
{
return new MyClass;
}
extern "C" void destroy_object( MyClass* object )
{
delete object;
}
MyClass::MyClass()
{
x = 20;
}
void MyClass::DoSomething()
{
cout<<x<<endl;
}
pengguna_kelas.cc
#include <dlfcn.h>
#include <iostream>
#include "myclass.h"
using namespace std;
int main(int argc, char **argv)
{
/* on Linux, use "./myclass.so" */
void* handle = dlopen("myclass.so", RTLD_LAZY);
MyClass* (*create)();
void (*destroy)(MyClass*);
create = (MyClass* (*)())dlsym(handle, "create_object");
destroy = (void (*)(MyClass*))dlsym(handle, "destroy_object");
MyClass* myClass = (MyClass*)create();
myClass->DoSomething();
destroy( myClass );
}
Di Mac OS X, kompilasi dengan:
g++ -dynamiclib -flat_namespace myclass.cc -o myclass.so
g++ class_user.cc -o class_user
Di Linux, kompilasi dengan:
g++ -fPIC -shared myclass.cc -o myclass.so
g++ class_user.cc -ldl -o class_user
Jika ini untuk sistem plugin, Anda akan menggunakan MyClass sebagai kelas dasar dan mendefinisikan semua fungsi yang diperlukan secara virtual. Penulis plugin kemudian akan mengambil dari MyClass, menimpa virtual dan mengimplementasikan create_object
dan destroy_object
. Aplikasi utama Anda tidak perlu diubah dengan cara apa pun.
Berikut ini adalah contoh shared class library shared.[h,cpp] dan modul main.cpp yang menggunakan library tersebut. Ini adalah contoh yang sangat sederhana dan makefile dapat dibuat jauh lebih baik. Tapi itu berhasil dan dapat membantu Anda:
shared.h mendefinisikan kelas:
class myclass {
int myx;
public:
myclass() { myx=0; }
void setx(int newx);
int getx();
};
shared.cpp mendefinisikan fungsi getx/setx:
#include "shared.h"
void myclass::setx(int newx) { myx = newx; }
int myclass::getx() { return myx; }
main.cpp menggunakan kelas,
#include <iostream>
#include "shared.h"
using namespace std;
int main(int argc, char *argv[])
{
myclass m;
cout << m.getx() << endl;
m.setx(10);
cout << m.getx() << endl;
}
dan makefile yang menghasilkan libshared.so dan menautkan main dengan pustaka bersama:
main: libshared.so main.o
$(CXX) -o main main.o -L. -lshared
libshared.so: shared.cpp
$(CXX) -fPIC -c shared.cpp -o shared.o
$(CXX) -shared -Wl,-soname,libshared.so -o libshared.so shared.o
clean:
$rm *.o *.so
Untuk benar-benar menjalankan 'main' dan menautkan dengan libshared.so Anda mungkin perlu menentukan jalur pemuatan (atau meletakkannya di /usr/local/lib atau yang serupa).
Berikut ini menentukan direktori saat ini sebagai jalur pencarian untuk perpustakaan dan menjalankan main (sintaks bash):
export LD_LIBRARY_PATH=.
./main
Untuk melihat bahwa program tersebut ditautkan dengan libshared.so Anda dapat mencoba ldd:
LD_LIBRARY_PATH=. ldd main
Cetakan di mesin saya:
~/prj/test/shared$ LD_LIBRARY_PATH=. ldd main
linux-gate.so.1 => (0xb7f88000)
libshared.so => ./libshared.so (0xb7f85000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e74000)
libm.so.6 => /lib/libm.so.6 (0xb7e4e000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0xb7e41000)
libc.so.6 => /lib/libc.so.6 (0xb7cfa000)
/lib/ld-linux.so.2 (0xb7f89000)
Di atas jawaban sebelumnya, saya ingin meningkatkan kesadaran tentang fakta bahwa Anda harus menggunakan idiom RAII (Resource Acquisition Is Initialisation) agar aman dari penghancuran penangan.
Berikut adalah contoh lengkap yang berfungsi:
Deklarasi antarmuka:Interface.hpp
:
class Base {
public:
virtual ~Base() {}
virtual void foo() const = 0;
};
using Base_creator_t = Base *(*)();
Konten pustaka bersama:
#include "Interface.hpp"
class Derived: public Base {
public:
void foo() const override {}
};
extern "C" {
Base * create() {
return new Derived;
}
}
Penangan perpustakaan bersama dinamis:Derived_factory.hpp
:
#include "Interface.hpp"
#include <dlfcn.h>
class Derived_factory {
public:
Derived_factory() {
handler = dlopen("libderived.so", RTLD_NOW);
if (! handler) {
throw std::runtime_error(dlerror());
}
Reset_dlerror();
creator = reinterpret_cast<Base_creator_t>(dlsym(handler, "create"));
Check_dlerror();
}
std::unique_ptr<Base> create() const {
return std::unique_ptr<Base>(creator());
}
~Derived_factory() {
if (handler) {
dlclose(handler);
}
}
private:
void * handler = nullptr;
Base_creator_t creator = nullptr;
static void Reset_dlerror() {
dlerror();
}
static void Check_dlerror() {
const char * dlsym_error = dlerror();
if (dlsym_error) {
throw std::runtime_error(dlsym_error);
}
}
};
Kode klien:
#include "Derived_factory.hpp"
{
Derived_factory factory;
std::unique_ptr<Base> base = factory.create();
base->foo();
}
Catatan:
- Saya meletakkan semuanya di file header untuk keringkasan. Dalam kehidupan nyata, Anda tentu saja harus membagi kode Anda antara
.hpp
dan.cpp
file. - Untuk mempermudah, saya mengabaikan kasus di mana Anda ingin menangani
new
/delete
kelebihan muatan.
Dua artikel yang jelas untuk mendapatkan detail lebih lanjut:
- C++ buka mini how-to
- Pemuatan Dinamis C++ dari Objek Bersama saat Waktu Proses