c++classpolymorphismabstract-classstate-pattern

State pattern error in C++ (no suitable constructor)


class Tool {
public:
    virtual void mouseUp();
    virtual void mouseDown();
    virtual ~Tool();
};

class SelectionTool : public Tool {
    void mouseDown() override {
        std::cout << "SelectionTool icon\n";
    }

    void mouseUp() override {
        std::cout << "Draw a dashed rectangle\n";
    }
};

class BrushTool : public Tool {
    void mouseDown() override {
        std::cout << "BrushTool icon\n";
    }

    void mouseUp() override {
        std::cout << "Draw line\n";
    }
};

class Canvas {
    Tool _currentTool;
public:
    void mouseDown() {
        _currentTool.mouseDown();
    }

    void mouseUp() {
        _currentTool.mouseUp();
    }

    Tool getCurrentTool(){
        return this->_currentTool;
    }

    void setCurrentTool(Tool currentTool) {
        this->_currentTool = currentTool;
    }
};

int main(int argc, char *argv[]){
    auto george = std::make_unique<Canvas>();
    george->setCurrentTool(std::make_unique<BrushTool>());
    george->mouseDown();
    george->mouseUp();
    return 0;
}

No suitable user-defined conversion from "std::unique_ptr<Brush, std::default_delete>" to "Tool" exists.

I am following youtube course where that kind of polymorphism is used in Java and I tried to implement it in C++ but it doesnt work. Whats wrong with that code?


Solution

  • I suspect the polymorphism video you were using didn't use smart pointer types.

    You can't just use std::shared_ptr<T> as if it were the underlying type. They have get and set interfaces, but they are not a seamless replacement. If they were, they couldn't do their job!

    Using std::unique_ptr adds more conditions that you may not want to deal with right now. I'm just going to use std::shared_ptr here.

    If you want shared pointers, I'd suggest making a typedef to the shared pointer type and use that everywhere. You can assign std::shared_ptr<derived> to std::shared_ptr<base> similar to the inheritance rules for raw pointers. Just be sure you have a virtual base destructor, which you do.

    #include <iostream>
    #include <algorithm>
    
    class Tool {
    public:
        virtual void mouseUp() {}
        virtual void mouseDown() {}
        virtual ~Tool() {}
    };
    
    typedef std::shared_ptr<Tool> shared_tool_type;
    
    class SelectionTool : public Tool {
        void mouseDown() override {
            std::cout << "SelectionTool icon\n";
        }
    
        void mouseUp() override {
            std::cout << "Draw a dashed rectangle\n";
        }
    };
    
    class BrushTool : public Tool {
        void mouseDown() override {
            std::cout << "BrushTool icon\n";
        }
    
        void mouseUp() override {
            std::cout << "Draw line\n";
        }
    };
    
    class Canvas {
        shared_tool_type _currentTool;
    public:
        void mouseDown() {
            _currentTool.get()->mouseDown();
        }
    
        void mouseUp() {
            _currentTool.get()->mouseUp();
        }
    
        std::shared_ptr<Tool> getCurrentTool() {
            return this->_currentTool;
        }
    
        void setCurrentTool(shared_tool_type currentTool) {
            this->_currentTool = currentTool;
        }
    };
    
    int main(int argc, char* argv[]) {
        auto george = std::make_shared<Canvas>();
        george->setCurrentTool(std::make_shared<BrushTool>());
        george->mouseDown();
        george->mouseUp();
        return 0;
    }