使用ptr_vector时访问派生类的方法

时间:2012-07-20 12:01:03

标签: c++ boost casting polymorphism ptr-vector

设置

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,因此无法访问特定于子的方法。 需要某种形式的演员表,所以我想问题是:

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

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

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

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

Armor不需要这个功能,甚至没有类似的东西。

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

3 个答案:

答案 0 :(得分:2)

如果你必须转换为派生,那么这意味着你的设计很糟糕。

但如果你真的必须这样做(把它放在for循环中):

DerivedB * typeB = dynamic_cast< DerivedB * >( &*it );
if ( typeB != nullptr )
{
  std::cout << typeB->getB() << '\n';
} 

更好的方法是将getB()添加到接口,并在DerivedA中实现它(它可以返回一些虚拟值,或者如果确实需要则抛出)。

答案 1 :(得分:1)

Casting是一个非常难看的解决方案,而不是C ++。相反,你应该使用虚拟功能。

类似的东西:

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();

答案 2 :(得分: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()表示的实际函数是什么,就不可能对此进行评论。