vendredi 30 avril 2021

Polymorphic reference type

I have this simple piece of code (Command pattern) that doesn't work as expected.

Usually a polymorphic type would work when it's manipulated by either a pointer or a reference. So if Command is an interface and m_command is a reference, then SetCommand should work for different concrete types of Command (eg, CommandLightOn and CommandGarageDoorOpen) ? It turns out not the case. Once SimpleRemote is instantiated with CommandLightOn, the SetCommand has completely no effect. In this example, attempt to change the underlying object to CommandGarageDoorOpen has no errors, but no effect either.

It works fine if m_command in SimpleRemote is changed to pointer type. So the question is why reference type fails to work in this case?

class SimpleRemote
{
public:
    SimpleRemote( Command& command ) : m_command{ command } {}

    void SetCommand( Command& command )
    {
        m_command = command;  //<-- broken
    }

    void ButtonPressed()
    {
        m_command.execute();
    }

private:
    Command& m_command;
};

Output:

Light is on

Light is on #<-- expect that it prints "Garage door is up"

Full code of this example (simple Command pattern):

#include <iostream>
using std::cout;

class Light
{
public:
    void On()
    {
        cout << "Light is on\n";
    }

private:
};

class GarageDoor
{
public:
    void Up()
    {
        cout << "Garage door is up\n";
    }

private:
};


// the Command interface
class Command
{
public:
    virtual void execute() = 0;
};


class CommandLightOn : public Command
{
public:
    CommandLightOn( Light light ) : m_light{ light }{}

    void execute() override
    {
        m_light.On();
    }   

private:
    Light m_light;
};


class CommandGarageDoorOpen : public Command
{
public:
    CommandGarageDoorOpen( GarageDoor door ) : m_door{door} {}  

    void execute() override
    {
        m_door.Up();
    }

private:
    GarageDoor m_door;
};


class SimpleRemote
{
public:
    SimpleRemote( Command& command ) : m_command{ command } {}

    void SetCommand( Command& command )
    {
        m_command = command;
    }

    void ButtonPressed()
    {
        m_command.execute();
    }

private:
    Command& m_command;
};


int main()
{
    Light light;
    CommandLightOn light_on( light );

    SimpleRemote remote( light_on );
    remote.ButtonPressed();

    GarageDoor door;
    CommandGarageDoorOpen door_open( door );
    remote.SetCommand( door_open );
    remote.ButtonPressed();
}

Aucun commentaire:

Enregistrer un commentaire