所有派生类的公共接口

Common interface for all derived classes

本文关键字:接口 派生      更新时间:2023-10-16

我有一个基类Item,它存储一些数据,并授予访问器对它的访问权限,如:

class Item{
  (...)
public:
  int get_value();
  double get_weight();
  ItemMaterial get_material();
  (...)
}

然后我得到了派生类,如武器,装甲,增加了一些额外的数据:

class Weapon : public Item {
(...)
public:
  int get_dmg();
  (...)
}

我将这些item存储在某个容器中:

std::vector<Item*> inventory;
这里出现了接口的问题-如何访问派生类数据?我在想,有三个想法:

1。不同的接口

每个派生类添加自己的数据,如上所示,然后使用dynamic_cast:

Item *item = new Weapon;
int dmg = dynamic_cast<Weapon*>(item)->get_dmg();

2。通用接口类

创建一个包含所有访问器的接口类:

ItemInterface{
public:
  virtual int get_value() = 0;     //Item interface
  virtual double get_weight() = 0;
  (..)
  virtual int get_dmg() = 0;       //Weapon interface
  (...)
}

然后像这样:

Item : public ItemInterface{ (...) }

Weapon : public Item { (...) }

,最后我们可以访问数据:

Item *item = new Weapon;
int dmg = item->get_dmg();

3。模板和枚举的组合

这个想法可能有点奇怪:-)但是:

实现包含所有项目数据的enum:

enum class ItemData{
  Value,
  Weight,
  Material,  //Item data
  (...)
  Damage,    //Weapon data
  (...)
  Defense,   //armor data etc.
  (...)
  Null
}

和在基类中像这样的模板函数:

template<typename T>
T get_data(ItemData data){
  switch(data){
    case ItemData::Value: return _value; break;
    case ItemData::Damage: return _dmg; break;
    (...)
  }
}

并访问如下数据:

Item *item = new Weapon;
ind dmg = item->get_data<int>(ItemData::Damage);

= = =

你认为应该怎么做?如有任何建议,我将不胜感激!

致意。

你的第二个和第三个选择显然是而不是——每当你添加一个新类型的项时,你还必须改变基类或枚举——如果你需要任何基本形式的可维护性,这绝对不是你想要的。

这里出现了接口的问题-如何访问派生类数据

首先你必须考虑"你的代码在哪里做这个"?处理整个inventory的大部分代码应该只使用Item*的内容,只使用Item类的函数。

如果您有专门处理Weapon对象的代码,创建Weapon对象的地方(并插入inventory),也可以将它们添加到另一个变量中,也许是

形式的武器列表
std::vector<Weapon*> weapons;

或类Warrior的成员变量Weapon*或类似的东西(但要注意,现在将有两个指向相同对象的指针,因此必须考虑所有权)。因此,只处理武器的代码(例如,Warrior的成员函数)不会访问inventory来获取Weapon对象,它将始终直接使用Weapon*

如果出于某些原因,你必须编写一些代码来处理库存中的所有武器,那么编写一个函数,使用dynamic_cast提取所有Weapon对象(或者更好:使其成为迭代器函数),并在你需要访问所有武器时重用该函数。这样你就不用让动态强制转换弄乱你的代码,只要把它放在一个地方就可以了。

编辑:另一种选择(避免动态强制转换)是使用访问者模式,参见这篇文章。但我真的不喜欢那个帖子的答案,在呈现的形式中,它将暗示一个循环依赖"基础->访问者->派生->基础",这是一个糟糕的设计。

ValueType Weapon::getProprtyValue( PropertyType id ) {
   switch( id ) {
      case kWeaponProperty01: return m_weaponProperty01;
      ...
      default: return Item::getPropertyValue( id );
   }
}

您可以创建某种通用访问器方法,尽管它有一些限制,但它可能非常方便,特别是在内容编辑器,序列化等情况下