C++ dynamic_cast dowcast 失败
C++ dynamic_cast dowcast fails
在用 C++ 编写我的第一个大项目时,我遇到了一个我无法单独使用 google 和文档解决的问题。
我想不通为什么这个 dynamic_cast 失败了,即使 r 指向一个 MeshRenderer 对象。
for (RenderEventConsumer* r : d->getConsumers())
{
glUseProgram(mPickingShader->apiID);
MeshRenderer* m = dynamic_cast<MeshRenderer*>(r); //returns nullptr
if (m)
{
glUniform1ui(uPickingID, m->getOwner()->getID());
m->getMesh()->getUtillityBuffer().draw();
}
}
classRenderEventConsumer 有一个虚拟方法,是 MeshRenderer 的基础。
class MeshRenderer : public Component {...}
class Component : public GameObject {...}
class GameObject : protected TickEventConsumer, protected RenderEventConsumer, protected PhysicsTickEventConsumer {...}
根据Visual Studio,r 的 vftable 是正确的。
PS:这是我在 Whosebug 上的第一个问题,如果我违反了任何准则或缺少相关信息,请告诉我。
编辑:虽然我现在知道答案了,但为了清楚起见,我用一个独立的例子重现了错误:
#include <vector>
#include <iostream>
class RenderEventConsumer
{
virtual void onRender() {};
};
class RenderEventDispatcher
{
std::vector<RenderEventConsumer*> mConsumers;
public:
const std::vector<RenderEventConsumer*>& getConsumers()
{
return mConsumers;
}
void registerRenderEventConsumer(RenderEventConsumer* consumer)
{
mConsumers.push_back(consumer);
}
};
class GameObject : protected RenderEventConsumer {}; //changing this to public fixes dynamic_cast
class Component : public GameObject {};
class MeshRenderer : public Component
{
public:
void setup(RenderEventDispatcher& d)
{
d.registerRenderEventConsumer(this);
}
void onRender() override { }
};
int main()
{
RenderEventDispatcher d;
MeshRenderer* pt = new MeshRenderer();
pt->setup(d);
for (RenderEventConsumer* r : d.getConsumers())
{
MeshRenderer* m = dynamic_cast<MeshRenderer*>(r);
if (m)
{
std::cout << "not nullptr\n";
}
else
{
std::cout << "nullptr\n";
}
}
}
仅仅因为 RenderEventConsumer
是基数 MeshRenderer
,这并不意味着从 RenderEventConsumer
派生的所有 类 也(派生自)MeshRenderer
.
如果 MeshRenderer
不是指向对象的动态类型(的基础),则 dynamic_cast
将 return 为空。
这是一个可能发生的例子:
struct another_derived : RenderEventConsumer {} instance;
RenderEventConsumer* r = &instance;
// null, even through r is RenderEventConsumer*
dynamic_cast<MeshRenderer*>(r);
如果你发现你需要使用dynamic_cast
,那意味着设计被破坏了。考虑改用访问者模式。
感谢 Kaldrr。
解决方案是公开派生自 RenderEventConsumer。
class GameObject : public TickEventConsumer, public RenderEventConsumer, public PhysicsTickEventConsumer {...}
在用 C++ 编写我的第一个大项目时,我遇到了一个我无法单独使用 google 和文档解决的问题。
我想不通为什么这个 dynamic_cast 失败了,即使 r 指向一个 MeshRenderer 对象。
for (RenderEventConsumer* r : d->getConsumers())
{
glUseProgram(mPickingShader->apiID);
MeshRenderer* m = dynamic_cast<MeshRenderer*>(r); //returns nullptr
if (m)
{
glUniform1ui(uPickingID, m->getOwner()->getID());
m->getMesh()->getUtillityBuffer().draw();
}
}
classRenderEventConsumer 有一个虚拟方法,是 MeshRenderer 的基础。
class MeshRenderer : public Component {...}
class Component : public GameObject {...}
class GameObject : protected TickEventConsumer, protected RenderEventConsumer, protected PhysicsTickEventConsumer {...}
根据Visual Studio,r 的 vftable 是正确的。
PS:这是我在 Whosebug 上的第一个问题,如果我违反了任何准则或缺少相关信息,请告诉我。
编辑:虽然我现在知道答案了,但为了清楚起见,我用一个独立的例子重现了错误:
#include <vector>
#include <iostream>
class RenderEventConsumer
{
virtual void onRender() {};
};
class RenderEventDispatcher
{
std::vector<RenderEventConsumer*> mConsumers;
public:
const std::vector<RenderEventConsumer*>& getConsumers()
{
return mConsumers;
}
void registerRenderEventConsumer(RenderEventConsumer* consumer)
{
mConsumers.push_back(consumer);
}
};
class GameObject : protected RenderEventConsumer {}; //changing this to public fixes dynamic_cast
class Component : public GameObject {};
class MeshRenderer : public Component
{
public:
void setup(RenderEventDispatcher& d)
{
d.registerRenderEventConsumer(this);
}
void onRender() override { }
};
int main()
{
RenderEventDispatcher d;
MeshRenderer* pt = new MeshRenderer();
pt->setup(d);
for (RenderEventConsumer* r : d.getConsumers())
{
MeshRenderer* m = dynamic_cast<MeshRenderer*>(r);
if (m)
{
std::cout << "not nullptr\n";
}
else
{
std::cout << "nullptr\n";
}
}
}
仅仅因为 RenderEventConsumer
是基数 MeshRenderer
,这并不意味着从 RenderEventConsumer
派生的所有 类 也(派生自)MeshRenderer
.
如果 MeshRenderer
不是指向对象的动态类型(的基础),则 dynamic_cast
将 return 为空。
这是一个可能发生的例子:
struct another_derived : RenderEventConsumer {} instance;
RenderEventConsumer* r = &instance;
// null, even through r is RenderEventConsumer*
dynamic_cast<MeshRenderer*>(r);
如果你发现你需要使用dynamic_cast
,那意味着设计被破坏了。考虑改用访问者模式。
感谢 Kaldrr。
解决方案是公开派生自 RenderEventConsumer。
class GameObject : public TickEventConsumer, public RenderEventConsumer, public PhysicsTickEventConsumer {...}