0

設定

class Base
{
public:
    Base();
    virtual ~Base();
    int getType();
protected:
    int type;
};

class DerivedA : public Base
{
public:
    DerivedA() { this->type = 1; };
    ~DerivedA();

    int getA() { return 1;};
};

class DerivedB : public Base
{
public:
    DerivedB() { this->type = 2; };
    ~DerivedB();

    int getB() { return 2;};

};

目標

両方の派生クラスのオブジェクトを含むベクトルを持ち、子固有のメソッドにアクセスできるようにします。

現在の「解決策」

int main()
{
    typedef boost::ptr_vector<Base> BasePtr;
    BasePtr vec;

    // Fill vec with some stuff 
    vec.push_back(new DerivedA());
    vec.push_back(new DerivedB());
    vec.push_back(new DerivedA());
    vec.push_back(new DerivedB());

    typedef BasePtr::iterator BaseIter;

    for ( BaseIter it = vec.begin(); it != vec.end(); it++ ) {

       if (it->getType() == 1) {
          std::cout << it->getA() << '\n';
       } else {
          std::cout << it->getB() << '\n';
       }    

    }

    return 0;
 }

問題

明らかに、「it」はDerivedAまたはDerivedBとして認識されないため、子固有のメソッドにアクセスできません。何らかの形のキャストが必要なので、質問は次のとおりだと思います。

イテレータを正しい派生クラスに適切にキャストするにはどうすればよいですか?

たぶん、このシナリオ全体を構築するためのより良い方法がありますか?

編集: 私は少し不明確だったようです。派生クラスのメソッドの目的は根本的に異なります。派生クラスArmorとWeaponを持つ基本クラスItemについて考えてみます。

この例では、たとえば、Weaponにfloatを返す可能性のある関数getDamage()がある理由がわかります。

この機能はアーマーには必要なく、似たようなものもありません。

この例では、ベクターを、任意の数とタイプのアイテムを含むことができる在庫として見ることができます。たぶん、スタックといくつかの用途があるアイテムでさえ(ポーションかもしれません)

4

3 に答える 3

2

派生にキャストする必要がある場合、それはあなたが壊れたデザインを持っていることを意味します。

しかし、本当にそうしなければならないのであれば、これでうまくいくでしょう(forループに入れてください):

DerivedB * typeB = dynamic_cast< DerivedB * >( &*it );
if ( typeB != nullptr )
{
  std::cout << typeB->getB() << '\n';
} 

より良いアプローチはgetB()、インターフェースに追加し、それをDerivedAに実装することです(ダミー値を返すか、本当に必要な場合はスローすることができます)。

于 2012-07-20T12:06:23.800 に答える
1

キャスティングはかなり醜い解決策であり、C++'yではありません。代わりに、仮想関数を使用する必要があります。

何かのようなもの:

class Base
{
public:
    virtual int get() = 0;

    // ...
};

class DerivedA : public Base
{
public:
    int get() { return 1;};
};

class DerivedB : public Base
{
public:
    int get() { return 2;};
};

そうすれば、余分なタイプを用意する必要はなく、を呼び出すだけで済みますit->get();

于 2012-07-20T12:03:18.937 に答える
1

以下のようにdynamic_castを使用できます。

for ( BaseIter it = vec.begin(); it != vec.end(); it++ ) 
{
    DerivedA* dA = dynamic_cast<DerivedA*>(it);
    if(dA != NULL)
    {
      // Do whatever for DerivedA
    }

    // Similarly check for DerivedB

}  

多態性を利用するようにインターフェースを設計する以外に、ここから抜け出す簡単な方法はありません。つまり、基本クラスで関数シグネチャを定義し、それらを派生クラスに実装します。上記のforループは、理想的には、コンテナアイテムのタイプを認識しようとすべきではありません。getA()とgetB()で表される実際の関数が何であるかを知らずに、これについてコメントすることは不可能です。

于 2012-07-20T12:08:43.020 に答える