我有基类Item,它存储一些数据并通过访问器授予对它的访问权限,如:
class Item{
(...)
public:
int get_value();
double get_weight();
ItemMaterial get_material();
(...)
}
然后我有了像Weapon,Armor这样的派生类,它们增加了一些额外的数据:
class Weapon : public Item {
(...)
public:
int get_dmg();
(...)
}
我将这些物品存放在某个容器中:
std::vector<Item*> inventory;
接下来是接口的问题 - 如何访问派生类数据?我在想,并有3个想法:
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 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);
===
您认为应如何做?我会很感激任何建议!
的问候。
答案 0 :(得分:2)
你的第二个和第三个选项显然是不的方式 - 每当你添加一个新类型的项目时,你还必须更改基类或枚举 - 这绝对不是什么如果您的代码中需要任何基本形式的可维护性,那么您希望这样做。
接下来是接口问题 - 如何访问派生类数据
首先,您必须考虑“您的代码将在何处执行此操作”?处理整个inventory
的大多数代码只应将内容用作Item*
,仅使用Item
类中的函数。
如果你有专门处理Weapon
个对象的代码,那么创建Weapon
个对象(并插入inventory
)的地方也可以将它们添加到另一个变量中,也许
std::vector<Weapon*> weapons;
或类Weapon*
的成员变量Warrior
或类似的东西(但要注意,您现在将有两个指向相同对象的指针,因此您必须考虑所有权)。因此,仅处理武器的代码(例如,Warrior
的成员函数)不会访问inventory
来获取Weapon
对象,它将始终使用Weapon*
直。
如果由于某些原因,您必须编写一些代码来处理库存中所有武器的某些内容,那么请编写一个函数,使用Weapon
提取所有dynamic_cast
个对象(甚至更好) :使它成为迭代器函数),并在需要访问所有武器时重用此函数。因此,您不会使用动态强制转换混乱您的代码,但请将其保留在一个位置。
编辑:另一种选择(避免动态演员)使用访客模式,请参阅this post。但我真的不喜欢那篇文章的答案,在提交的表格中它将暗示循环依赖“Base - &gt; Visitor - &gt; Derived - &gt; Base”,这是恕我直言,这是一个糟糕的设计。
答案 1 :(得分:1)
ValueType Weapon::getProprtyValue( PropertyType id ) {
switch( id ) {
case kWeaponProperty01: return m_weaponProperty01;
...
default: return Item::getPropertyValue( id );
}
}
您可以制作某种通用访问器方法,虽然它有一些限制,但它可以非常方便,特别是在内容编辑器,序列化等情况下。