sを使用してAdam Rosenfield のソリューションを2 番目に使用しmap
ます。ただし、より高いレベルの機能を取得するためのより低いレベルのインターフェイスは、dlsym()
ルックアップを使用することです。
Shape
汎用インターフェースがファイルShape.hpp
にあり、次の形式であると仮定します。
class Shape {
public:
virtual ~Shape () {}
//...virtual methods
virtual void draw () const = 0;
};
template <typename DERIVED>
class ShapeBridge : public Shape {
public:
static Shape * create () { return new DERIVED; }
};
struct ShapeFactory {
Shape * (*create) ();
};
新しい共有オブジェクトを作成し、それを既存の実行中の実行可能ファイルに動的にリンクすることによって、新しい形状を動的に追加したいとします。次に、共有オブジェクトの動的ロードを使用して具体的なファクトリ関数を取得する、ある種の抽象ファクトリを作成できるようになりました。
#include <string>
#include <map>
#include <dlfcn.h>
struct ShapeCreator {
void *dlhandle_;
void *factory_;
ShapeCreator () : dlhandle_(0), factory_(0) {}
void open (std::string libname) {
dlhandle_ = dlopen(libname.c_str(), RTLD_LAZY);
factory_ = dlsym(dlhandle_, "factory");
}
void close () { if (dlhandle_) dlclose(dlhandle_); }
ShapeFactory * factory () const {
return static_cast<ShapeFactory *>(factory_);
}
static Shape * create (std::string name) {
static std::map<std::string, ShapeCreator> lookup;
static std::string dir = "./";
if (lookup[name].factory() == 0) {
lookup[name].open(dir + name + ".so");
}
return lookup[name].factory()->create();
}
};
共有オブジェクトには、次の実装を含めることができます。
// gcc -fPIC -shared -Wl,-export-dynamic -o Circle.so Circle.cpp -lc
#include "Shape.hpp"
#include <iostream>
class Circle : public ShapeBridge<Circle> {
public:
//..
void draw () const { std::cout << "I am a circle.\n"; }
};
extern "C" {
ShapeFactory factory = { Circle::create };
}
次に、形状を動的に作成します。
Shape *s = ShapeCreator::create("Circle");
s->draw();
もちろん、実際にその名前を (構成ファイルやユーザー入力などから) 動的に取得した場合、この例はもう少し興味深いものになります。