Search code examples
c++castingpolymorphismdynamic-cast

C++ dynamic_cast dowcast fails



While writing my first big project in C++, I encountered a problem which I wasn´t able to solve using google and documentation alone.

I cannot figure out, why this dynamic_cast fails, even though r is pointing to a MeshRenderer Object.

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();
    }
}

The class RenderEventConsumer has a virtual method and is a base of MeshRenderer.

class MeshRenderer : public Component {...}
class Component : public GameObject {...}
class GameObject : protected TickEventConsumer, protected RenderEventConsumer, protected PhysicsTickEventConsumer {...}

According to Visual Studio the vftable of r is correct. enter image description here

PS: This is my first question on stackoverflow, please let me know if I violated any guideline or am missing relevant information.

EDIT: Although I know the answer now, I reproduced the error with a standalone example for clarity:

#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";
        }
    }
}

Solution

  • Thanks to Kaldrr.
    The solution was to derive publicly from RenderEventConsumer.

    class GameObject : public TickEventConsumer, public RenderEventConsumer, public PhysicsTickEventConsumer {...}