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 属性之前很容易忘记检查指针是否为空,如下所示:

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 中为 B1s 和 B2s 设置两个单独的向量,但这似乎也不是一个好主意,因为我需要能够轻松设置 a 和 b。有什么想法吗?

4

3 回答 3

1

您所拥有的一切都很好:只要您不将NULLs 存储在bases指针向量中,就无需对迭代器返回的值进行空值检查。不幸的是,指针向量是多态对象容器的唯一选择。您可以创建一个共享指针向量来简化删除处理,但基本思想将保持不变。

于 2013-03-29T18:51:36.950 回答
0

您可以检查您正在访问的项目是否是您正在寻找的正确子类类型,但要执行此操作,您需要包含运行时类型信息 (rtti)。

然后,如果它是某种类型而不是 null,您可以将其强制转换为该类型并调用正确的函数。

您也可以使用动态_cast,尽管要使其正常工作,您需要再次使用 rtti,这与检查自己然后进行静态转换基本相同。

于 2013-03-29T18:50:06.257 回答
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; }   
};

然后你可以调用它->getSubValue() 来获取你请求的子值。

这是我的意见,有很多方法可以解决这个问题,但这是我根据您提供的信息提出的建议。

于 2013-03-29T18:54:18.523 回答