0

共通ベース から派生した一連のオブジェクトがありますApiObject。すべての ApiObjects を個別のデータ構造に登録できる必要がありますが、基本クラスではなく、作成されるオブジェクトの実際のアドレスが必要です (多重継承を使用しています)。

ApiObject派生オブジェクトのアドレスがわからないため、コンストラクターにオブジェクトを登録するコードを配置できません。また、派生クラスのコンストラクターに入れることもできません。別の派生クラスを実際に構築しているかどうかを知る方法がないためです (たとえば、 classBが から継承されA、両方を構築できる場合)。

したがって、私が見る唯一のオプションは、次のように、オブジェクトを作成するたびに登録関数を明示的に呼び出すことです。

B* b = new B(...);
RegisterObject(b);

ただし、毎回この関数を呼び出すことを覚えておく必要があるため、これはあまり良い解決策ではないようです。

なぜこれを行っているのかを説明するために、より多くのコンテキストを提供する必要があると思います。オブジェクトはオーバーロードされた new 演算子を介して作成され、オブジェクトが作成されたコンテキスト (Lua 状態) を知る必要があります。例えば

Foo* object = new(L) Foo(...);
// Foo is derived from ApiObject, and we want ApiObject to have a reference to L

現在、それはやや洗練されていない方法で行われています - new 演算子は、オブジェクトの前に追加のバイトを割り当て、そこに L ポインターを格納し、オブジェクトの型を記述するための追加データをいくつか追加します。次に、基本クラスは init 関数を介してこの「メタデータ」へのポインターを受け取ります。
それ以外の場合、最初に頭に浮かぶのは仮想関数ですが、コンストラクターから呼び出すことはできないため、ベースApiObjectポインターを登録する必要がありますが、後で仮想関数を呼び出すだけです。それは私の現在の実装よりもきれいです。

4

4 に答える 4

2

に必要なタイプは何RegisterObjectですか? を受け取る場合 は、最終的な階層に関係なく、Base*のコンストラクターから呼び出すことができます。Base他の型を取る場合は、その型のコンストラクターから呼び出します。から派生したすべてのクラスから呼び出すのではなくBase取得する型から派生したクラスに対してのみ呼び出します。

RegisterObjectを受け取り、派生クラスの関数Base*から呼び出すと、最初に、渡したポインターが に変換されますBase*RegisterObject派生オブジェクトへのポインタを受け取ることはなく、派生オブジェクト内の へのポインタのみを受け取りBaseます。

于 2013-04-01T11:10:49.653 に答える
0

基本コンストラクターから登録関数を呼び出すことができます。基本デストラクタを仮想にするだけです。アドレスは、基本クラスと派生クラスで同じになります。オブジェクト全体が作成される前にポインターアドレスを使用しないでください。

すべてのオブジェクトが完全に作成されると、ポインター アドレスは、仮想関数を介して安全に使用したり、派生クラスに動的にキャストしたりできます。

于 2013-04-01T11:21:12.520 に答える
0

さらに、登録を実行する CRTP クラスから、登録するすべてのオブジェクトを派生させることができます。

template<class T>
struct registarar_t<T>
{
  registarar_t()
  {
     register(derived());
  }

  T* derieved()
  {
    return static_cast<T*>(this);
  }
}

struct IWantToRegister : registrar_t<IWantToRegister>, ApiObject
{
}

また、注意してください。derived()ポインターは正しいですが、オブジェクトはまだ初期化されていません (親コンストラクターでアクセスします)。

于 2013-04-01T11:01:57.747 に答える