因此,我正在研究基于文本的RPG,但遇到了一个问题。我目前正在从角色的 list 中装备武器。我正在尝试使程序能够告诉他们他们想要装备的项目是否为Weapon
类。这是相关代码的片段:
Item tempChosenWeapon = myInventory.chooseItem();
cout << tempChosenWeapon.getName() << endl;
Item *chosenWeapon = &tempChosenWeapon;
cout << chosenWeapon->getName() << endl;//THE CODE WORKS UP TO HERE
Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
cout << maybeWeapon->getName() << endl;
现在,
Weapon
是Item
的子类,这就是为什么我使用动态强制转换-试图将chosenWeapon
类型的Item
更改为Weapon
以便比较这两个类。 (我正在使用这些cout<<
或测试从这些对象调用函数是否有效)。我的程序编译完成,一切正常,直到我们进入
maybeWeapon->getName()
为止,在该程序中程序崩溃。我已经研究了很多,但是我只是不明白我在做什么错。任何答案或替代建议,不胜感激!谢谢! 最佳答案
问题
问题是您尝试对Weapon
进行动态转换,但实际上指向的对象是由Item
构造的真实副本,而不是子类。取消引用后,结果为nullptr
和UB!
为什么呢
假设 list 中只有Weapon
个对象。摘要中的第一条指令是您邪恶的根源:
Item tempChosenWeapon = myInventory.chooseItem();
这是语句是
Item
对象的副本构造。如果源对象是Weapon
,则它将是 sliced 。稍后,您将指针指向该对象:
Item *chosenWeapon = &tempChosenWeapon;
但是,此
Item*
并不像您认为的那样指向Weapon
对象。它指向一个真正的原始Item
对象!因此,当您在此处进行动态投射时: Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
该代码将发现
choosenWeapon
不是Weapon*
,并且dynamic_cast
的结果将是nullptr
。到现在为止,这不一定是灾难。但是,当您取消引用此指针时,您会得到UB: maybeWeapon->getName() // OUCH !!!!!!
解
检查
dynamic_cast
是否成功(即结果不是nullptr
)可以防止崩溃,但不能解决根本问题。问题甚至可能比预期的更深:现实中
myInventory.chooseItem()
返回什么类型?它是一个普通的物品吗?然后,库存中可能已经有 slice 问题!如果要使用多态:
Item
的赋值:您需要调用多态clone()
函数,并确保此克隆的目标具有兼容的类型。 从解决方案开始,它是这样的:
Item* chosenWeapon = myInventory.chooseItem(); // refactor choosItem() to return a pointer.
cout << chosenWeapon->getName() << endl;
Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
if (maybeWeapon)
cout << maybeWeapon->getName() << endl;
else cout << "Oops the chosen item was not a weapon" <<endl;
如果仍然无法解决问题,则您的库存容器将存在缺陷。在这种情况下,请在打开带有容器代码的单独问题之前先查看this question
关于c++ - 多态与动态类型转换,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51974105/