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;
 }

问题

显然“它”既不被识别为 DerivedA 也不被识别为 DerivedB,因此无法访问子特定方法。需要某种形式的演员表,所以我想问题是:

如何正确地将迭代器转换为正确的派生类?

也许有更好的方法来构建整个场景?

编辑: 似乎我有点不清楚。派生类中方法的目的是根本不同的。考虑具有派生类 Armor 和 Weapon 的基类 Item。

在这个例子中,你可以看到为什么,例如,Weapon 有一个函数 getDamage(),它可能会返回一个浮点数。

Armor不需要此功能,甚至没有类似的功能。

在此示例中,您可以将向量视为可以包含任意数量和类型的项目的库存。甚至可能有堆叠和一些用途的物品(可能是药水)

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

您可以使用 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 回答
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 回答