2011-07-05 11 views
1

私はC++フレームワークを書く際に問題があります。ユーザーは、フレームワークのBaseClassによって派生したクラスを含む共有ライブラリを作成し、インスタンスの派生クラスを返すためにextern "C" createInstance()メソッドを実装することで、その作業をフレームワークに公開できます。したがって、フレームワークは、dlsym()を使用して共有ライブラリを介してcreateInstance-Methodを呼び出すことによって、ユーザークラスにアクセスできます。C++のファクトリパターン:明示的なcreateInstance() - メソッドの自動生成

フレームワークで
class BaseClass{} 
class UserClass : public BaseClass{} 

extern "C"{ 
    BaseClass* UserXcreateInstance(){ 
    return new UserClass(); 
    }       
} 

typedef BaseClass* (*CreateInstance)(); 
void* handle; 
CreateInstance createInstance; 
handle = dlopen("libUserLibrary.so", RTLD_LAZY | RTLD_GLOBAL); 
createInstance = reinterpret_cast <CreateInstance*> dlsym(handle, "UserXcreateInstance"); 
BaseClass* userX = createInstance(); 

私の質問:それはUserXcreateInstance()を生成することが可能です - ユーザーが考える必要が `tをするように、各ユーザーライブラリ内の冗長である方法を、それについて?

別のアプローチは、私が直接介して、任意のユーザクラスのコンストラクタを呼び出していることを考えていた...

は、私はそれがテンプレート+マクロで可能だろうと思ったが、私はまだこれを行うための方法を発見していませんdlsymと適切な名前のmangling。 (私は設定ファイルから任意の名前空間+クラス名を知っています)しかし、私はこれは適切な解決策、特にコンストラクタ呼び出しは通常の関数呼び出しと同じではないと思っています...しかし、非常に興味深い...

答えて

4

私はユーザーの一部分のコードなしでこれを自動的に作成する方法を想像することはできません。私は、おそらくマクロを使用して、それを簡素化する方法を想像することができます:

#define OBJECT_CREATOR(X) \ 
    extern "C" {   \ 
     BaseClass *UserXCreateInstance() {\ 
      return new X(); \ 
     }\ 
    } 

、ユーザーがちょうど彼のcppファイルを置く必要があります。

OBJECT_CREATOR(UserClass); 
+0

ありがとうございます、1行は4より良いです;) – Dudero

+0

あなたは大歓迎です! – bcsanches

3

私は、ユーザー関数を呼び出すと仮定しますdlsym経由されます絶対的な要件ではありません。

CRTPを使用すると、簡単に達成できます。静的ヘルパーオブジェクトのコンストラクタは、関連するデータを中央リポジトリに登録します。

template <typename UserClass> 
class BaseClass 
{ 
    private: 
    class UserObjectFactory 
    { 
     UserObjectFactory() 
     { 
     std::string myname = typeid(UserClass).name(); 
     CentralObjectFactory::instance()->register(this, myname); 
     } 
     BaseClass* XUserCreateInstance() 
     { 
     return new UserClass; 
     }    
    }; 
    static UserObjectFactory factory; 
}; 

ユーザーコードは単純です:

class MyClass : public BaseClass<MyClass> 
{ 
    // whatever 
}; 

はおそらく、CentralObjectFactoryインスタンスがstd::stringからUserObjectFactoryに(マルチ)マップのいくつかの種類が含まれていることは、次のように行く必要があります。

mynameは、衝突を避けるために、typeid(UserClass).name()の代わりに一意に生成された文字列に初期化することができます。

各ユーザーのクラスの単一のオブジェクトが必要な場合は、UserObjectFactoryを作成してUserClassのインスタンスを作成し、代わりに登録することができます。

std::string myname = typeid(UserClass).name(); 
    CentralObjectRepository::instance()->register(XUserCreateInstance(), myname); 

このデザインはお客様のニーズを満たしていますか?

+0

あなたのアイデアは非常に興味深いと思うが、それは私のために働いていない。静的ヘルパークラスのコンストラクタは達成されません...これはユーザの共有ライブラリのdlopen-callによって行われるべきですか、それとももっと前提条件がありますか? – Dudero

+0

ああ、すごく残念ですが、これは実際には機能しません。私はそれを修正することができればお知らせします。 –