2

タイプ ID 名でオブジェクトを作成する便利なオブジェクト ファクトリ テンプレートがあります。実装は非常に明白です:オブジェクトクリエーター関数へObjectFactoryのマップが含まれています。std::string次に、作成されるすべてのオブジェクトがこのファクトリに登録されます。

これを行うには、次のマクロを使用します。

#define REGISTER_CLASS(className, interfaceName) \
   class className; \
   static RegisterClass<className, interfaceName> regInFactory##className; \
   class className : public interfaceName

どこRegisterClassですか

   template<class T, class I>
   struct RegisterClass
   {
      RegisterClass()
      {
         ObjectFactory<I>::GetInstance().Register<T>();
      }
   };

使用法

class IFoo
{
public:
   virtual Do() = 0;
   virtual ~IFoo() {}
}

REGISTER_CLASS(Foo, IFoo)
{
   virtual Do() { /* do something */ }
}

REGISTER_CLASS(Bar, IFoo)
{
   virtual Do() { /* do something else */ }
}

クラスは、ファクトリで同時に定義および登録されます。

問題は、regInFactory...静的オブジェクトが .h ファイルで定義されているため、すべての翻訳単位に追加されることです。同じオブジェクト作成者が複数回登録され、さらに重要なことに、静的ストレージ期間を持つ冗長なオブジェクトが多数存在します。

このようなエレガントな登録を行う方法はありますか (クラス名とインターフェイス名をコピー/貼り付けするのではなく)、冗長な静的オブジェクトを世界中に広げないでください。

優れたソリューションに VC++ 固有の拡張機能 (C++ 標準に準拠していないもの) が必要な場合は、それで問題ありません。

4

4 に答える 4

5

それで、変数定義をヘッダーファイルに入れたいですか?移植可能な方法があります: テンプレート クラスの静的変数です。したがって、次のようになります。

template <typename T, typename I>
struct AutoRegister: public I
{
    // a constructor which use ourRegisterer so that it is instantiated; 
    // problem catched by bocco
    AutoRegister() { &ourRegisterer; } 
private:
    static RegisterClass<T, I> ourRegisterer;
};

template <typename T, typename I>
RegisterClass<T, I> AutoRegister<T, I>::ourRegisterer;

class Foo: AutoRegister<Foo, IFoo>
{
public:
    virtual void Do();         
};

IFoo 非仮想の継承を保持していることに注意してください。そのクラスから複数回継承するリスクがある場合は、仮想にする必要があります。

于 2009-08-21T07:00:40.537 に答える
3

Cygonの答えはおそらくあなたが必要としているものですが、正確に何のために登録されているかによっては、怠惰な登録で逃げることもできます。

登録を特別な基本クラスに移動し、マクロのインターフェイス以外にそれを添付します。

内部コンストラクターはローカル静的フラグを使用するため、各クラスは最初のインスタンス作成時に1回だけ登録されます。

おそらくコンパイルされませんが、私が意味するものを取得する必要があります。

template<className, interfaceName>
class RegistratorBase
{
public:
     RegistratorBase()
     {
          static bool registered = false;
          if(!registered)
                ObjectFactory<interfaceName>::GetInstance().Register<className>();
     }
};

#define REGISTER_CLASS(className, interfaceName) \
  class className : public interfaceName, private RegistratorBase<className, interfaceName>
于 2009-08-21T06:25:04.617 に答える
2

マクロを変更して、REGISTER_CLASSがクラスを宣言せずに登録するだけにするのはなぜですか?

これにより、インターフェイスを実装しながら別のクラスから派生できるようになり、登録を.cppファイルに入れて、1つのコンパイルユニットにのみ含めることができ、ヘッダーの依存関係を最小限に抑えることができます(オブジェクトファクトリヘッダーをに含める必要はありません)。すべてのパブリックヘッダー)。

リンカがグローバルの1つだけを選択し、未使用のグローバルを破棄するようにするVC++拡張機能があります。問題の変数はグローバルに表示される必要があります(=静的ではなく、コンパイラが拡張機能をサポートしていない場合、リンカーエラーが発生します)。

__declspec( selectany )

使用法は次のようになります。

#define REGISTER_CLASS(className, interfaceName) \
  class className; \
  __declspec( selectany ) \
    RegisterClass<className, interfaceName> regInFactory##className; \
  class className : public interfaceName
于 2009-08-21T05:42:50.210 に答える