0

2 つのクラスと無料の関数で基本的なことを試しています。まず、2 つのクラスがあります。

struct BASE{
    BASE(int a = 0):a_(a){};
    virtual ~BASE(){};
    virtual void foo(){std::cout << "BASE " << std::endl;}
    int a_;
};

struct DERIVED: public BASE{
    DERIVED():BASE(){};
    void foo(){std::cout << "DERIVED " << std::endl;}
};

次に、std::vector (または boost::ptr_vector) を埋めます。

std::vector<BASE* > vec;    
vec.push_back( new BASE(2));
vec.push_back( new DERIVED);

関数 foo を呼び出すと、仮想のものはうまく機能しませんが、2 つの無料関数を作成すると、次のようになります。

void foo(BASE*   a, DERIVED*   b){
    std::cout << " mix base/derived " << std::endl;
}

void foo(BASE*   a, BASE*   b){
    std::cout << " full base " << std::endl;
}

私が行った場合

foo(vec[0], vec[1]); //failed

メッセージを受け取ります

full base

私は BASE* のベクトルを持っているので、それは論理的ですが、私のフリー関数への適切な呼び出しを取得するためにとにかく存在しますか? 継承が必要なので、このコンテナーをいっぱいにする必要があるため、2 つのクラスを実際に分離することはできません。

さらに、最後にベクトルがランダムにいっぱいになるため、適切にキャストする方法を事前に知ることはできません。

4

3 に答える 3

2

回避策を得る最も簡単な (そして最も速い) 方法は、もう 1 つの仮想関数を導入して派生クラスを一意に識別することです ( intenum値、またはを使用typeid)。したがって、後でそれを呼び出して、 の背後にある正確な派生クラス (またはベース) を認識し、その型に対してBASE*行うことができます。dynamic_cast

解決しようとしている問題についての詳細は提供されていません...ダブルディスパッチ(または何らかの種類)を実装する場合は、既存のソリューションについて完全な調査を行ったことを確認してください...

しかし、通常、必要な場合dynamic_castは、設計に問題があることを意味します(ドメインのOOPモデル)...

于 2012-12-05T13:43:43.247 に答える
0

自分が何であるかを事前に知らないのと同じようにvec[i]、コンパイラも知りません。関数のオーバーロードの解決はコンパイル時のプロセスですが、ポリモーフィズムは実行時のプロセスです。

したがって、それはvoid foo(BASE* a, BASE* b)バージョンを呼び出します。

dynamic_castつまり、可能なすべての派生クラスにキャストしようとしない限り、やりたいことは不可能です。0オブジェクトのタイプが間違っている場合に返されます。

dynamic_castただし、多くの人は、 の使用は設計が悪いことを示していると主張します 。そして、それは高価でもあります。

于 2012-12-05T13:39:01.153 に答える
0

そのためには、次のような動的ディスパッチが必要です。

void foo(BASE *a, BASE *b) {
  if (DERIVED *bb = dynamic_cast<DERIVED*>(b)) {
    foo(a, bb);
  } else {
    std::cout << " full base " << std::endl;
  }
}

を使用したくない場合は、何らかの形式のクラス識別子 (たとえば、 ) を返すdynamic_cast仮想関数を追加し、各派生クラスでこれをオーバーライドしてから、この関数の戻り値に基づいて呼び出しをフォークすることができます (とともに)。BASEenumstatic_cast

于 2012-12-05T13:43:09.950 に答える