0

すべて基本クラス ポインターのベクトルに格納されているサブクラスのプロパティとメソッドにときどきアクセスする必要があるため、プログラムで設計上の問題が発生しています。私のコードは次のようになります。

class B1;
class B2;
class Base {
  private:
  int id, a, b;

  public:
  virtual int getA() { return a; }
  virtual int getB() { return b; }
  virtual B1 *getB1() { return NULL; } //seems like a bad idea
  virtual B2 *getB2() { return NULL; }  //to have these two functions
  Base(int newId) { id = newId; }
};

class B1 : public Base {
   private:
   int x;

   public:
   int getX() { return x; }
   B1 *getB1() { return this; }
};

class B2 : public Base {
   private:
   int y;

   public:
   int getY() { return y; }
   B2 *getB2() { return this; }
};

class Thing {
   private:
   std::vector<Base*> bases;

   void addBase(Base *base) { bases.push_back(base); }
   void doB1Stuff();
   void doB2Stuff();
   void setAandB(int ID, int newA, int newB); //set a and b of one of the elements in bases vector based upon the id given
};

問題は、次のように Thing で x または y にアクセスする必要がある場合です。

void Thing::doB1Stuff() {
  for(std::vector<Base*>::iterator it = bases.begin(); it != bases.end(); ++it) {
    if (it->getB1()) {
      //do stuff with b1
    }
  }
}

上記のコードは機能するはずですが、次のように B1/B2 プロパティを使用する前にポインターが null であるかどうかを簡単に確認するのを忘れてしまう可能性があるため、お勧めできません。

void Thing::doB2Stuff() {
  for(std::vector<Base*>::iterator it = bases.begin(); it != bases.end(); ++it) {
    std::cout << it->getY(); //I believe this will crash the program if a NULL pointer is returned
  }
}

したがって、私の質問は次のとおりです。サブクラスのプロパティにアクセスする良い方法は何ですか? Thing で B1 と B2 の 2 つの別々のベクトルを使用することを考えていましたが、a と b を簡単に設定できるようにする必要があるため、それも良い考えではないようです。何かご意見は?

4

3 に答える 3

1

NULLポインタのベクトルに s を格納しない限りbases、イテレータから返された値を null チェックする必要はありません。残念ながら、ポリモーフィック オブジェクトのコンテナーには、ポインターのベクトルしか選択肢がありません。共有ポインターのベクトルを作成して、削除の処理を簡素化できますが、基本的な考え方は変わりません。

于 2013-03-29T18:51:36.950 に答える
0

おっしゃる通り、これは問題に対処する優れた方法ではありdynamic_castません。使用するオブジェクトを安全に判断する方法として使用できますが、それは私にとって悪いコードの匂いです。

サブ プロパティにアクセスする代わりに、Base クラスで必要な値を返す仮想関数を作成します。

例:

class Base {
  private:
  int id, a, b;

  public:
  virtual int getA() { return a; }
  virtual int getB() { return b; }
  virtual int getSubValue() = 0; // 
  Base(int newId) { id = newId; }
};

class B1 : public Base {
   private:
   int x;

   public:
   int getSubValue() { return x; }   
};

class B2 : public Base {
   private:
   int y;

   public:
   int getSubValue() { return y; }   
};

次に、 it->getSubValue() を呼び出すだけで、要求したサブ値を取得できます。

これは私の意見であり、これを処理する方法はたくさんありますが、これはあなたが提供した情報に基づいて提案するものです.

于 2013-03-29T18:54:18.523 に答える
0

アクセスしているアイテムが探している正しいサブクラス タイプであるかどうかを確認できますが、これを行うにはランタイム タイプ情報 (rtti) を含める必要があります。

次に、特定の型で null でない場合は、その型にキャストして正しい関数を呼び出すことができます。

また、動的_cast を使用することもできますが、これを機能させるには rtti が再び必要であり、基本的には自分自身をチェックしてから静的キャストを行うのと同じです。

于 2013-03-29T18:50:06.257 に答える