3

編集:わかりましたが、これはケースを大きく変更するため、より正確なシナリオは次のとおりです。

私が現在持っている階層は、これに多少似ています。

class IBase() { virtual void Foo() = 0; };

class Base() : public IBase { virtual void Foo() { } };

class IDerived() { virtual void Bar() = 0; };

template<typename TT, typename TB, typename... TI>
class Derived : public Base, public IDerived { virtual void Bar() {}};

template<typename TT, typename TB, typename... TI>
IBase* CreateDerived() { return new Derived(); }

IBase* derived = CreateDerived<some types...>();

オブジェクトをキャストして関数を呼び出そうとすると、Visual Studio でエラーが発生します。

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  

派生を介した IBase インターフェイスのすべての呼び出しは正常に機能しますが、派生を IDerived にキャストしようとすると、関数呼び出しでエラーが発生します。

IDerived* d = (IDerived*)derived;
d->Bar(); <- boom error ;) 

そのようなキャストは違法だと思いますが、IDerived インターフェイス メソッドにアクセスできるようにするにはどうすればポインターをキャストできますか (できれば、dynamic_cast がなければ、適切でポータブルなハックがあればそれを使用したいと思います ;))? 適切なvtableが使用され、すべてが正常に機能するように、ポインターへのオフセットを計算することは可能ですか?

私はかなり長い間プログラミングを行ってきましたが、大量のインターフェースとテンプレートを備えた設計されたシステムに対するこれらの空想を常に回避してきましたが、今では自分で作成する運命にあります。

編集:ご覧のとおり、これはトリッキーで困難になります。テンプレート化されているため、取得している Derived の正確なタイプはわかりません。関数 CreateDerived もテンプレート化されており、インターフェイスを返します。

また、要件の 1 つは、dynamic_cast を使用しないことです (プロジェクトでは RTTI が無効になっています)。

4

1 に答える 1

1

あなたはクロスキャストを実行しています。IBaseIDerivedは無関係です。Derived最初にキャストし、次に にキャストする必要がありますIDerivedstatic_castC キャストではなくキャストを使用した場合、コンパイラはコンパイル時にこれをキャッチします。

IBaseC キャストを使用したため、 が本当に であることを知っていると思いますDerivedが、そうでない場合は、 を使用dynamic_castしてクロス キャストを安全に実行することもできます。

EDIT:RTTIを使用できず、オブジェクトの動的タイプがわからない場合は、仮想継承を使用dynamic_castしてウィンドウから出てください。呼び出すCreateDerivedと、オブジェクトの動的な型を知っているように見えるので(テンプレート引数のため) 、呼び出しstd::map<IBase*, IDerived*>後にtoを使用して、ポインターをキーと値の両方としてマップに挿入できます.CreateDerived<TT, TB, TI...>()static_castIBase*Derived<TT, TB, TI...>*

RTTI を有効にするだけです。これは複雑になっています。>.<

EDIT 2: あるいは、 が指しているオブジェクトIBase*も から派生していることを知っているようですIDerived*。クラス階層を変更できる場合は、両方から派生した抽象基本クラスを作成しIBaseIDerivedこのDerived新しい基本クラスから派生させることができます。次にstatic_cast、 からIBase*階層内の新しいクラスに移動し、次に に移動できIDerived*ます。

次のようになります。

class IBase { virtual void Foo() = 0; };

class Base : public IBase { virtual void Foo() { } };

class IDerived { virtual void Bar() = 0; };

class BaseAndDerived : public Base, public IDerived { };

template<typename TT, typename TB, typename... TI>
class Derived : public BaseAndDerived { virtual void Bar() {}};
于 2013-09-13T10:30:11.963 に答える