Item tempChosenWeapon = myInventory.chooseItem();
这是Item。不是来自Item 的类型。这是一个Item。
C++ 中的值具有已知类型。
cout << tempChosenWeapon.getName() << endl;
一切都好,但请停止using namespace std;
Item *chosenWeapon = &tempChosenWeapon;
这是一个指向Item 的指针。我可以证明它不是多态的,因为它是一个指向Item 类型实例的指针。编译器可能可以证明这一点。
cout << chosenWeapon->getName() << endl;//THE CODE WORKS UP TO HERE
好的,这会重复上一次调用。
Weapon *maybeWeapon = dynamic_cast<Weapon*>(chosenWeapon);
这确定性地返回nullptr。 chosenWeapon 是 Item*,我们知道它指向 Item,而 Item 不是 Weapon。
cout << maybeWeapon->getName() << endl;
这取消引用nullptr。
在 C++ 中有多种处理多态性的方法。但你必须考虑一下。
首先,你想要值语义吗?价值语义意味着某物的副本就是它的副本。事物不指代其他事物;他们就是那些东西。
您可以使用多态值来处理值语义,但这需要一些工作。你写了两个类;值包装器和内部pImpl。
内部pImpl有一个std::unique_ptr<Impl> Impl->clone() const方法,复制时值包装器调用它。
你这样写你的界面:
template<class D>
struct clonable {
std::unique_ptr<D> clone() const = 0;
};
struct ITarget;
struct IItem:clonable<IItem> {
virtual std::string get_name() const = 0;
virtual bool can_equip( ITarget const& ) const = 0;
~virtual IItem() {}
};
struct Target;
struct Item {
using Impl = IItem;
explicit operator bool() const { return (bool)pImpl; }
IItem* get_impl() { return pImpl.get(); }
IItem const* get_impl() const { return pImpl.get(); }
template<class D>
D copy_and_downcast() const& {
auto* ptr = dynamic_cast<typename D::Impl const*>( pImpl.get() );
if (!ptr) return {};
return D(ptr->clone());
}
template<class D>
D copy_and_downcast() && {
auto* ptr = dynamic_cast<typename D::Impl*>( pImpl.get() );
if (!ptr) return {};
pImpl.release();
return D(std::unique_ptr<typename D::Impl>(ptr));
}
std::string get_name() const {
if (!*this) return {};
return pImpl->get_name();
}
bool can_equip(Target const& target)const{
if (!*this) return false;
if (!target) return false;
return pImpl->can_equip( *target.get_impl() );
}
Item() = default;
Item(Item&&) = default;
Item& operator=(Item&&) = default;
Item(std::unique_ptr<IItem> o):pImpl(std::move(o)) {}
Item(Item const& o):
Item( o?Item(o.pImpl->clone()):Item{} )
{}
Item& operator=( Item const& o ) {
Item tmp(o);
std::swap(pImpl, tmp.pImpl);
return *this;
}
private:
std::unique_ptr<IItem> pImpl;
};
这可能有错误,对你来说可能太复杂了。
其次,您可以使用引用语义。
在这种情况下,您希望从数据中返回 shared_ptr<const T> 或 shared_ptr<T>。或者你可以半途而废,从你的 chooseItem 函数返回一个 unique_ptr<T> 副本。
引用语义真的很难正确。但是你可以直接使用dynamic_cast 或dynamic_pointer_cast。
std::shared_ptr<Item> chosenWeapon = myInventory.chooseItem();
if (!chosenWeapon) return;
std::cout << chosenWeapon->getName() << std::endl;
auto maybeWeapon = dynamic_pointer_cast<Weapon>(chosenWeapon);
if (maybeWeapon)
std::cout << maybeWeapon->getName() << std::endl;
else
std::cout << "Not a weapon" << std::endl;