3

これはおそらく変な質問ですが、私が質問するのには十分な理由があります。

私の質問の要点は、クラス階層で2レベルの派生がある例を考えると、次のとおりです。

メインベースクラス:

class Animal
{
  virtual void Draw() = 0;
};

派生クラス:

class Dog : public Animal
{
  virtual void Draw()
  {
    // draw a generic dog icon or something...
  }
};

さらなる派生:

class Corgi : public Dog
{
  virtual void Draw()
  {
    // draw a corgi icon...
  }
};

Corgiさて、クラス内から、「this」ポインターをポインターに永続的にダウンキャストし、Dogそれを別の場所にアニマルとして渡すことができるようになりたいと思っています。この別の場所は、仮想メソッドではなく、Draw関数を呼び出してメソッドを取得できるようになります。私はこれが奇妙であることを知っていますが、繰り返しますが、私にはそれをしたいという漠然とした正当な理由があります.DogCorgi

さまざまなキャスティング オペレーターをすべて試しましたが、うまくいきませんでしたが、これをうまくやってのける一貫した方法はありますか? 過去に、私は適切に使用しなかったために自分自身に問題を引き起こしdynamic_cast、その結果、ポインターに同様の状態が発生しました。今回はそれを活かせるかな。

編集: 上記の例では、私が達成しようとしていることを明確に示していない可能性があるため、実際の目標について詳しく説明します。

私は、しばらく使用してきたスクリプト システムにリンクする基本クラスの実装を登録するための省略形を達成しようとしています。スクリプト システムは基底クラスに依存していますIScriptContext実際のコード関数へのアクセスとメンバー変数へのアクセスを容易にするため。内部的に基本クラスは、メンバー関数のアドレスとメンバー変数のアドレスを登録します。これらは、後でルックアップ テーブルを介してディスパッチ/アクセスされます。クラス派生階層の適切なサポートをスクリプト システムに追加しようとしています。これらのインターフェイスの基本クラス バージョンを分離できると、時間を節約し、プロセス全体をクリーンにすることができると考えました。利用可能な基本クラスをスクリプト インタープリターに登録します。これを実現する方法は他にもあります。たとえば、利用可能な基本クラスごとに必要なメソッドごとにクラス固有の関数ポインタを登録する方法があります (例: this->Dog::CallFunctionthis->Dog::SetMemberthis->Dog::GetMember.) しかし、インターフェイスを使用すると、後で必要に応じて少し簡単に変更できるようになると考えました。

そのすべてが何らかの意味を成すことを願っています。

ありがとう!

4

4 に答える 4

6

オブジェクトがありCorgiます。あなたはできる:

  1. すべての呼び出しに修飾子をDog使用して、どこでもオブジェクトとして扱います (例: )。これにより、仮想ディスパッチが失われ、質問の読み方から望むものではないことはほぼ確実です。Dog::ptr->Dog::draw();

  2. から実際に新しいDogオブジェクトを構築しますCorgistatic_cast他のタイプを変換するか、暗黙の変換を引き継ぐように、法線でこれを行うだけです(例: Corgi c; Dog d(c);)。

これらは利用可能なオプションです。a を保持したいCorgiが、自動的にどこでも a であるふりをすることDogは、合理的でも合法的でもないため、言語はそれを提供しません。

于 2012-12-28T22:00:10.210 に答える
2

Tomalakは、あなたが利用できる主な選択肢の2つをすでに概説しています。

  • 修飾されたコールを使用する、または

  • のコピーDogとしてを作成します。DogCorgi

これらに加えて、あなたはすることができます

  • 単純なラッパーを使用する

例えば

class LooksLikeDog
    : public Dog
{
private:
    Dog*  realObject_;

    LooksLikeDog( LooksLikeDog const& );                    // No such.
    LooksLikeDog& operator=( LooksLikeDog const& );         // No such.

public:
    LooksLikeDog( Dog& other )
        : realObject_( &other )
    {}

    // Just for exposition: not implementing this does the same.
    virtual void draw() override { Dog::draw(); }

    // Example of other method that may need to be implemented:
    virtual void bark() override { realObject_->bark(); }
};

しかし、最善の解決策は、おそらく設計を修正することです。;-)

于 2012-12-28T22:26:55.137 に答える
2

まず、あなたのデザインに欠陥があるように見えると言うことから始めましょう。

ただし、呼び出したい階層内の関数を明示的に指定できます。

Corgi* corgi = new Corgi;
corgi->Dog::draw();

これにより、 からではなく からdrawメソッドが呼び出されます。(あなたが求めていることを正しく理解できたと思います)。DogCorgi

于 2012-12-28T21:59:03.547 に答える
0

コーギー描画関数を実装し、親の実装を呼び出します。

virtual void Corgi::Draw() 
{ 
    Dog::draw(); 
}
于 2012-12-28T23:02:05.260 に答える