9

基本クラスの仮想関数を介してオブジェクトの派生型を取得しようとしています。私はこれを書きましたが、コンパイルされません:

struct base {
  virtual base& get_this() {
    return *this;
  }
};

struct derived : base {
  virtual derived& get_this() override {
    return *this;
  }

  void fn();
};


int main () {
  base* pd = new derived();
  derived& x = pd->get_this(); /*ERROR*/
  x.fn();
  return 0;
}

derived&... というエラーが表示されます: aから a を初期化できませんbase。は仮想なのでget_this、なぜaではなくa をpd->get_this()返すのですか? 前もって感謝します!base&derived&

編集:

有益な回答をくださった皆様に感謝し、返信が遅れたことをお詫びします。上記がコンパイルされない理由を理解するだけでなく、問題の解決策にも興味があることを元の投稿で指定する必要がありました。私の主な問題はfn、クラスに固有でありderived、基本クラスを介して呼び出すことができないことです。キャストを使用すると問題は確実に解決しますが、適切な型を取得するためだけに if else 構造を使用してコードを書くのは嫌いです (また、Scott Meyers はキャストに対してアドバイスしています :)) 。答えは、キャストが進むべき道であることを示しているようです。これは、私の問題に対するより「エレガントな」解決策を無視していないことを少なくとも安心させます。再度、感謝します!

4

5 に答える 5

8

C++ 共変の戻り値の型のサポートは、派生型を既に知っている場合にのみ機能します。基本クラスをおそらく派生クラスにダウンキャストするには、単純に base_ref が実際の派生型と一致するかどうかを判断するために使用しますdynamic_cast<derived>(base_ref)

int main () {
    base* pd = new derived();
    derived& x = dynamic_cast<derived&>(*pd); // Will throw an exception if pd 
                                          // isn't a 'derived'
    x.fn();
    return 0;
}

または、次のようにします。

int main () {
    base* pd = new derived();
    derived* x = dynamic_cast<derived*>(pd); // Will return nullptr if pd isn't
                                         // a 'derived'
    if(x) {
        x->fn();
    }
    else {
        // dynamic_cast<derived*> failed ...
    }
    return 0;
}

は派生クラスの共変の戻り値の型をサポートしていますが、他の回答で説明されているように、ここで基本クラス ( ) を呼び出して取得することはできませんpd->get_this()

RTTIや例外処理を使用できない場合、または厳密な型バインディングが必要な場合 (vtable オーバーヘッドなしで)、コンパイル時に型の準拠をチェックするために静的ポリモーフィズムを検討することもできます。

于 2013-10-21T19:27:37.683 に答える
3

の静的タイプはpdですbase *。したがって、コンパイラがメンバー関数get_this()を検索すると、 のみが見つかりbase::get_this()ます。の戻り値の型はbase::get_this()ですbase&。これは に変換できませんderived&。したがって、エラー。

于 2013-10-21T18:28:43.940 に答える
1

C++ は、共変の戻り値の型をサポートしています。つまり、ポインターを介してオブジェクトを呼び出すget_this()と、derived呼び出さbaseれるのは派生の実装です。

base::get_thisただし、これは呼び出しによって が得られるという意味ではありませんderived&。の戻り値の型はbase::get_thisですbase&。オブジェクトを取得したい場合は、ポインターを介しderivedて呼び出す必要があります (またはにダウンキャストします)。これは、戻り値の型の共分散が Java、C++、D でどのように機能するかに注意してください...get_thisderivedbase&derived&

base* pbase = new base();
base* pderived = new derived();
derived* pderived2 = new derived();

base& a = pbase->get_this();        // call implementation in base, return base&
base& b = pderived->get_this();     // call implementation in derived, return base&
derived& c = pderived2->get_this(); // call implementation in derived, return derived&
于 2013-10-21T19:02:47.413 に答える