[英]When is a `static_cast<Base*>(static_cast<void*>(derived))` from a pointer to a derived class valid?
[英]static_cast from base class pointer to derived class pointer is invalid
我正在创建一个简单的测试实体组件系统。 我有几个派生类的基本Component
类。 然后,我有几个将某些逻辑应用于这些组件的系统。
// Component.h
// ------------
class Component
{
public:
Component();
~Component();
}
// ControlComponent.h
// -------------------
#include <string>
#include "Component.h"
class ControlComponent : public Component
{
public:
std::string input = ""; // store simple input instruction
ControlComponent();
~ControlComponent();
};
// ControlSystem.cpp
void ControlSystem::update(Entity* entity)
{
vector<Component*>* components = entity->getComponents();
for (Component* component : *components)
{
PositionComponent* pc = static_cast<PositionComponent*>(component);
ControlComponent* cc = static_cast<ControlComponent*>(component);
if (pc != nullptr && cc != nullptr)
{
std::cout << "Which direction would you like to go?" << std::endl;
std::string input;
std::cin >> input;
cc->input = input; // application breaks here
// Apply some logic...
}
}
}
当我从基本Component*
static_cast
到任何派生组件( PositionComponent*
或ControlComponent*
)并且两个结果都不为nullptr
(即nullptr
成功),我得到了无效值,例如cc->input
无法读取字符串等字符
我将实体工厂中的组件连接起来,如下所示:
void EntityFactory::wireUpPlayer(Entity* player)
{
player->addComponent(new HealthComponent());
player->addComponent(new ControlComponent());
player->addComponent(new PositionComponent());
}
并且addComponent的实现如下:
void Entity::addComponent(Component* component)
{
m_components.push_back(component);
}
这些组件显示为具有有效的内存地址,因此我不确定问题出在哪里。
static_cast
在运行时不检查有效性; 如果强制转换已编译,则它将在运行时假定转换正常。 如果您不强制转换为空指针,则static_cast
的结果将不会为空指针。 要获得检查的dynamic_cast
转换,您需要dynamic_cast
而这又要求将指针转换为指向多态类型,即具有至少一个虚函数的类型。 这意味着将Component
更改为至少具有一个虚拟功能。
当我从基本
Component*
static_cast
到任何派生组件(PositionComponent*
或ControlComponent*
)并且两个结果都不为nullptr
(即nullptr
成功)...
从基类转换为派生类时, static_cast
告诉编译器:“相信我,我知道我在做什么。” 换句话说,如果它甚至可能合法,它将“成功”并返回non- nullptr
。 如果在运行时不合法,则尝试使用一个类的实例就像是另一个类的实例那样,您将获得未定义的行为。
请改用dynamic_cast
。
正如Pete Becker和Josh Kelley所说,请使用dynamic_cast
并且我相信您还需要将至少一个函数设置为virtual
。 如果您不这样做,则编译器将不会记录继承,而且dynamic_cast
可能仍会返回nullptr
。 执行继承时,建议将类析构函数设为虚拟。 当需要在派生类的析构函数中处置非托管资源并且您只有指向基类的指针时,这也是一种好习惯,只要只要析构函数是虚拟的,就将调用派生类的析构函数。 这里有一篇文章对此进行了解释: 什么时候使用虚拟析构函数?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.