gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:46:33 27 4
gpt4 key购买 nike

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

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

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

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

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

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/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com