c++ - SFML C++ 绘制到 RenderWindow 纯虚函数运行时失败

标签 c++ c++11 sfml

我正在制作标签和按钮类。标签基本上用作附加到按钮的文本,而按钮具有按钮的纹理和其他一些东西。

我想让事情自动化,这样你就不必单独调用每个按钮的绘制方法,所以我创建了一个 ButtonManager 类,它有一个 vector 和一个静态绘制成员函数。

问题是,该 vector 包含接口(interface)类,而不是常规类(用于 future Button 类型的扩展)。

在描述问题之前,让我们看一下代码:

包含所有按钮基本界面的文件:

class ButtonManager;

class ButtonBase{
    typedef ButtonManager Manager;
public:
    virtual int getType() = 0;
    virtual void draw(sf::RenderWindow& target) = 0;
};

这个很简单

使用 ButtonManager 的文件(有点长):

class ButtonManager{
    typedef ButtonBase* ptr;
    static std::vector<ptr> container;
    inline static ptr& __at(uint index)
    {
        if (index > container.size())    throw std::exception("bad index");
        return container[index];
    }

    static void __push(const ptr& Pointer)    {    container.push_back(Pointer);    }
    static void __pop()    {    container.pop_back();    }
    /*
        Private to hide them from potentional unintended push or pop
    */
public:
    enum{
        DRAW_ALL = -1
    };

    static void draw(sf::RenderWindow& target, uint toDraw = DRAW_ALL)
    {
        std::cout << "container: " << container.size() << "\n";
        if (toDraw == DRAW_ALL)
            for(auto& a : container)
            {
                a->draw(target);
            }
        else
            container.at(toDraw)->draw(target);
    }
    struct ClassImpl{
        inline static ptr& at(uint index)    {    return ButtonManager::__at(index);    }
        inline static void push(const ptr& Pointer)    {    ButtonManager::__push(Pointer);    }
        inline static void pop()    {    ButtonManager::__pop();    }
    };
};

std::vector<ButtonManager::ptr> ButtonManager::container;

最后是包含按钮本身的文件:

class Button final : public ButtonBase{
    typedef ButtonBase parent;

    mutable Label label;
    mutable sf::Texture texture;
    mutable sf::Sprite buttonImage;
    mutable std::function<void(Button&, ButtonState/* enum class */)> callBack;
public:
    Button() {}

    Button(const sf::Vector2f& position, const sf::Vector2f& size, const std::string& imagePath,\
           sf::IntRect& rect/*unsued*/, std::function<void(Button&, ButtonState)> f_ptr,\
           const Label& _label) : label(_label), callBack(f_ptr)

        //some code
        Manager::ClassImpl::push(this);
    }

    //copy construct
    Button(const Button& b);

    //copy assign
    Button& operator=(const Button& b);

    //move assign
    Button(Button&& b);

    //move construct
    Button& operator=(Button&& b);

    int getType()
    {
        return 1;
    }

    void draw(sf::RenderWindow& window)
    {
        window.draw(buttonImage);
        window.draw(label.getText());
    }
};

注意:我尝试制作 ButtonManager::ptr bth ButtonBase* 和 std::shared_ptr,但没有成功

我遇到的问题是,当我调用 ButtonManager::draw(someSFMLWindow) 时,当它尝试调用 a->draw(target) 时,它将写入控制台:

R6025 - 纯虚函数调用

当我调试代码时,在调用Button::draw的第一行(window.draw(buttonImage))时出现错误。

问题出在哪里?有任何提示问题出在哪里吗?

最佳答案

到处使用静态通常会暴露出糟糕的设计选择。静态成员变量本质上是突破所有“状态”的全局变量。我不会详细说明为什么应该避免全局变量,但是围绕这个主题有足够的线索,所以我相信您会找到一些东西。我也不是说静态函数在 C++ 中没有一席之地,它只是使用“静态”来避免以封装方式处理对象的烦恼,这并不是真正的解决方案。

正如评论中所建议的,通过从 sf::Drawable 派生来实现您想要的效果真的很容易。

class Widget : public sf::Drawable {
    virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const = 0;
}

class Button final : public Widget {
    void draw(sf::RenderTarget &target, sf::RenderStates states) const {
        target.draw(m_button, states);
    }

    sf::Sprite m_button;
}

class WidgetManager {
public:
    void draw(sf::RenderWindow &window) {
        for(const auto &widget : m_widgets)
            window.draw(widget);
    }

private:
    std::vector<std::unique_ptr<Widget>> m_widgets;
}

当然,您需要添加用于创建和删除小部件以及管理可见性(另一个小部件前面/后面显示的内容)的功能。您可以为某些小部件创建静态创建工厂函数,但除此之外,您不应该创建静态函数,而应该考虑设计以及如何减少类依赖性并防止“inject-WidgetManager-everywhere”综合症。

关于c++ - SFML C++ 绘制到 RenderWindow 纯虚函数运行时失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21294413/

相关文章:

c++ - 我的迭代器没有按照预期的方式工作

c++ - 如何为Windows Office 文档之类的文件添加属性?

c++ - 奇怪的迭代器行为 + unordered_set 的段错误

c++ - Allegro 5 游戏无法使用 GCC 编译

c++ - 传递参数为 `const` 的奇怪效果

c++ - std::find 在空 vector 上是否会导致未定义的行为?

c++ - 当我超过第一个 getline() 的输入数组大小时,第二个 getline 或其他输入函数不起作用

c++ - 允许在派生类上使用流运算符

c++ - 无法让 SFML 音乐工作

c++ - 如何缩短图像的文件名/路径,使其适用于所有机器