为什么我的虚方法在C ++中被跳过?

时间:2013-04-11 00:49:07

标签: c++ pointers factory factory-pattern roguelike

长话短说:我正在研究的程序就像流氓一样 - 尽管这个问题并不是真的需要。

以下是与此问题相关的类的层次结构树:

                                     Entity
                        Item                     Creature
                  Weapon     Armor     

我在Entity中声明了几个虚函数,它们在从它派生的类中也是虚函数。

我不确定如何说出我的问题,但我会解释问题并在下面发布代码。我有一个工厂类型类,名为 ItemFactory,,它打开一个xml文件并使用我制作的简单解析器 - 并创建Item对象并设置它们的值。它有一个返回 Item 指针的方法。在我的主文件中,我声明/定义了一个 ItemFactory 对象。当需要在游戏中删除时,我会使用类型为的指针, 并调用该方法随机选择指向。所有这一切都很完美..

这是问题所在。 实体有一个名为 dumpObject()的虚方法,它打印出变量的状态。 dumpObject()中也是虚拟的。当从项目调用它时,该方法首先使用以下方法调用实体转储:

                 Entity::dumpObject();

然后它会转储它自己的变量..我对武器 Armor 做同样的事情,除非使用它:

                 Item::dumpObject();

我的问题:

由于 ItemFactory 同时包含 - 武器 Armor ,主程序中的指针指向项目,不应该调用 “itemPointer-> dumpObject();” 转储Weapon / Armor的值(取决于它指向的......)还会将值转储到中,这也会转储实体中的值?

当我运行代码时,唯一被转储的部分是Item和Entity中的部分。

如果我需要提供更多详细信息,请与我们联系。有什么建议?谢谢!

这是代码片段

我包含了标题,只是尽量减少我发布的代码量


Item.cpp

void Item::dumpObject(){
    cout << "Item:" << endl;
    dumpObjectData();
}

void Item::dumpObjectData(){
    Entity::dumpObjectData();
    cout << "        [Weight] " << getWeight() << endl;
    cout << "         [Value] " << getValue() << endl;
    cout << "      [Quantity] " << getQuantity() << endl;
    cout << "   [Enchantment] " << getEnchantment() << endl;
}

Entity.cpp

void Entity::dumpObject(){
    cout << "Entity:" << endl;
    dumpObjectData();
}

void Entity::dumpObjectData(){
    XMLSerializable::dumpObjectData(); //XMLSerialization handles parsing

    cout << "          [Name] " << getName() << endl;
    cout << "   [DisplayChar] " << getDisplayChar() << endl;
    cout << "    [Properties] " << endl;

    for( auto it = m_vProperties.begin(); it != m_vProperties.end();it++ ){
            cout << "       - " << (*it) << endl;
    }
}

Weapon.cpp

void Weapon::dumpObject(){
    cout << "Weapon:" << endl;
    dumpObjectData();
}

void Weapon::dumpObjectData(){
    Item::dumpObjectData();

    cout << "        [Damage] " << getDamage() << endl;
    cout << "         [Range] " << getRange() << endl;
    cout << "      [Accuracy] " << getAccuracy() << endl;
    cout << "      [AmmoType] " << getAmmoType() << endl;
    cout << "          [Type] " << getType() << endl;
}

Armor.cpp

void Armor::dumpObject(){
    cout << "Armor:" << endl;
    dumpObjectData();
}

void Armor::dumpObjectData(){
    cout << "calls to dump item data"<<endl;
    Item::dumpObjectData();
    cout << "calls to dump armor"<<endl;
    cout << "          [Type] " << getType() << endl;
    cout << "          [Slot] " << getSlot() << endl;
    cout << "    [ArmorValue] " << getArmorValue() << endl;

}

主要

    ItemFactory myItems = ItemFactory::instance();
    Item * pItem1 = myItems.generateItem();
    pItem1->dumpObject();



接头

Entity.h

#include "XMLSerializable.h"
#include <vector>

class Entity : public XMLSerializable {

public:
    Entity(void);
    virtual ~Entity(void);

    virtual void dumpObject();
    virtual void dumpObjectData();

};

Item.h

#include "Entity.h"

class Item : public Entity{

public:
    Item(void);
    virtual ~Item(void);

    virtual void dumpObject();
    virtual void dumpObjectData();

};


Weapon.h

#include "Item.h"

class Weapon : public Item {
public:
    Weapon(void);
    virtual ~Weapon(void);

    virtual void dumpObject();
    virtual void dumpObjectData();

};

Armor.h

#include "Item.h"

class Armor : public Item {
public:
    Armor(void);
    virtual ~Armor(void);

    virtual void dumpObject();
    virtual void dumpObjectData();

};

ItemFactory.cpp

ItemFactory & ItemFactory::instance(){
    static ItemFactory myObj;
    return myObj;
}

ItemFactory::ItemFactory(){
    m_mtRandom.seed( time(NULL) );
    fstream xmlFile;
    xmlFile.open("items.xml");
    vector<XMLSerializable*> pObjects;
    parseXML(xmlFile, pObjects);

    XMLSerializable * pObject;

    for(auto it = pObjects.begin(); it != pObjects.end(); it++){
            pObject = (*it);
            Item * pItem = dynamic_cast<Item*>(pObject);
            if (pItem != NULL){
                    m_vItems.push_back(pItem);
            }
    }
}


ItemFactory::~ItemFactory(){

}


Item * ItemFactory::generateItem() {
    vector<Item*> tempItems;

    for(auto it = m_vItems.begin(); it != m_vItems.end(); it++){
            tempItems.push_back((*it));
    }

    int randomItem = (m_mtRandom() % (m_vItems.size() - 1));


    Item * pItem = tempItems.at(randomItem);

    Item * pReturnValue = new Item(*pItem);

    return pReturnValue;
}

既然我已经完成了所有工作,我认为除了Main之外的任何代码都是必要的。大声笑我猜测我在Main中的指针的逻辑是错误的吗?

1 个答案:

答案 0 :(得分:4)

这是你的问题:

Item * pReturnValue = new Item(*pItem);

这会为您提供浅层副本,以便您不会获得ArmorWeapon

如果只需要给定基类实例的副本,请在基类中定义clone方法。

看起来您正在尝试使用prototype模式,因此您确实想要创建新实例?

class Entity : public XMLSerializable {

public:
    Entity(void);
    virtual ~Entity(void);

    virtual Entity* clone() const { return new Entity(*this);}

    virtual void dumpObject();
    virtual void dumpObjectData();

};

class Armor : public Item {
public:
    Armor(void);
    virtual ~Armor(void);
    virtual Armor* clone() const { return new Armor (*this);}
    virtual void dumpObject();
    virtual void dumpObjectData();

};

请注意clone()使用协变返回值。即返回值确实不同,但是当方法签名匹配且返回值彼此派生时,调用是虚拟的。

然后你可以写:

Item * pReturnValue = pItem->clone();

有关Prototype模式的背景信息,请参阅:Wikipedia