【问题标题】:Base object as argument to function which takes derived object基对象作为接受派生对象的函数的参数
【发布时间】:2019-08-12 21:17:12
【问题描述】:

我想编写一个函数,它将“Armor”类中的一个对象作为参数,但是,当我调用该函数时,我使用了基类“Item”中的一个对象。当然,我使用的这个物件,虽然可能只是一个“物品”,但也可能是一个“盔甲”。只有当我确定它是“Armor”时,我才想调用该函数。

就我而言,我将物品存储在向量中(这些物品可以是盔甲)。我想从向量中获取这个项目并用它调用函数(装备这个项目,我知道这是一件盔甲)。

class Item{
};

class Armor : public Item{
};

void equipArmor(Armor armor){ //Armor class argument
    //Equip the armor

}

int main(){
    vector<Item> items;
    Armor a;
    items.push_back(a);

    equipArmor(items[0]); //Call function with an "Item" as an argument (even though it is in fact also an "Armor")
}

【问题讨论】:

  • 您可能想查找静态和动态演员表。
  • 或者在此之前,继承?
  • 你的代码中没有显示继承关系。

标签: c++ function class inheritance arguments


【解决方案1】:

问题

你有一个Item 的向量。当你 push_backArmor 时,它将是 slicedItem。所以在向量中你不再有Armor,而只是一个普通的Item

这就是您的代码不起作用的原因。首先你不能用Item 调用你的equipArmor() 函数,因为它需要Armor 并且向下转换永远不会隐含。但即使你可以,你总是会传递一个Item 值,而永远不会传递一个Armor 值。

解决办法

要解决您的问题,您需要使用指针(更好的智能指针)或引用。

您需要能够使用polymorphic 类型并进行运行时类型确定的第一件事是在您的基类中至少有一个虚函数:

class Item{
public: 
    virtual ~Item() {} 
};

现在让我们将您的向量设为shared pointers 的向量。好消息是这些将确保对象在不再用于任何共享指针时将被销毁。因此,内存管理的麻烦更少,rule of 3 的麻烦更少:

vector<shared_ptr<Item>> items;

shared_ptr<Item> a = make_shared<Armor>();
items.push_back(a);
shared_ptr<Item> i = make_shared<Item>();
items.push_back(i);

equipArmor(items[0]); // lets just try the two possible cases
equipArmor(items[1]); 

最后,在你的函数中,你可以使用dynamic_pointer_cast安全的方式感知真实类型并采取相应的行动:

void equipArmor(shared_ptr<Item> item){ //Armor class argument
    shared_ptr<Armor> a = dynamic_pointer_cast<Armor>(item);  
    if (a) {
        cout << "Armor"<<endl; 
    }
    else cout << "Item"<<endl;     
}

Online demo

备注

如果你的类型不是多态的,你就不能dynamic_pointer_cast。您仍然可以使用static_pointer_cast 进行强制转换,但这是有风险的,因为它需要您确定强制转换的智能指针具有正确的类型。

如果您更喜欢原始指针,则适用相同的原则,但您可以分别使用dynamic_caststatic_cast。但同样,static_cast 要求您绝对确定类型。如果你有一个充满随机项目的向量,你怎么能呢?

【讨论】:

    【解决方案2】:

    您想从基类 (Item) 转换为子类 (Armor)。这是不可能的。

    如果items 是指向Items 的指针向量,则可以这样做。然后,如果您确定底层对象实际上是 Armour,则可以将 Item * 转换为 Armor *

    int main(){
        std::vector<Item *> items;
        Armor a;
        items.push_back(&a);
    
        // This only works if items[0] points to an Armor object
        equipArmor(*static_cast<Armor *>(items[0]));
    }
    

    【讨论】:

      猜你喜欢
      • 2014-01-01
      • 2018-08-04
      • 1970-01-01
      • 2022-11-21
      • 1970-01-01
      • 1970-01-01
      • 2014-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多