SFML 从派生的模板调用父函数 class

SFML calling parent's function from template derived class

我正在做一个自定义项目来学习 SFML,但我遇到了问题。我想做一个 'clickable' class,我可以在其中添加一些奇特的函数,我的第一个目标是编写一个 'onMouseOver' 函数,它可能与 Javascript 中的函数几乎相同。这是 class:

template <class object>
class clickable: public object{
private:
    sf::Vector2i mouse;
    object& aim;
    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const{ target.draw(aim, states); }
public:
    clickable(sf::Vector2i mouse,object& aim):mouse(mouse),aim(aim){}
    bool onMouseOver(sf::Vector2i mouse) {  
        float width = aim.getLocalBounds().width;
        float height = aim.getLocalBounds().height;
        if ((mouse.x >= aim.getPosition().x) && (mouse.x <= aim.getPosition().x + width) && (mouse.y >= aim.getPosition().y) && (mouse.y <= aim.getPosition().y + height))
            return true;
        else return false;
    }
};

这是我的主要内容:

    int main()
{
    sf::Font font;
    if (!font.loadFromFile("arial.ttf")) {
        std::cout << "Error!";
    }
    sf::RenderWindow window(sf::VideoMode(800, 600), "Title", sf::Style::Default);
    sf::Vector2i mouse = sf::Mouse::getPosition(window);
    vector<sf::Text> objects;
    objects.push_back(sf::Text("Test text.", font, 14));
    objects[0].setPosition(20, 20);
    clickable<sf::Text> stuff(mouse,objects[0]);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
            if (event.type == sf::Event::MouseMoved) {
                eger = sf::Mouse::getPosition(window);
            }
        }
        window.clear();
        window.draw(stuff);
        if (stuff.onMouseOver(mouse)) objects[0].setFillColor(sf::Color::Red);
        else objects[0].setFillColor(sf::Color::White);
        window.display();
    }
    return 0;}

我测试了这段代码(使用不同的变量名,因为我来自匈牙利)并且它有效。我的问题是,如果我想将“objects[0].setFillColor(sf::Color::Red)”更改为 'stuff.setFillColor(sf::Color::Red)',屏幕上什么也不会发生。我假设问题是我想从子 class 调用继承的父函数,但我不确定我能做些什么来解决这个问题。 我希望这是可以理解的,并对可能出现的语法错误感到抱歉,但正如我上面提到的,我不是母语人士。任何帮助将不胜感激!

提前致谢!

您有两个类型不同的对象 sf::Text:

  1. stuff
  2. stuff 的数据成员名为 aim

调用 stuffsetFillColor 方法将设置 stuff 的填充颜色,而不是 aim 的。但是stuffdraw方法完全服从aim的draw方法:

virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const{ target.draw(aim, states); }

aim 不知道 stuff 的填充颜色,因此 window.draw(stuff) 将做与以前完全相同的事情。

解决方案是重新设计您的 clickable class,这取决于您的意图。为什么您既要继承模板 class 又要拥有该 class 类型的数据成员?

现在最简单的事情可能是重新实现 sf::TextsetFillColor 方法作为 clickable 的新方法:

void clickable::setFillColor( const Color & color ) {
    aim.setFillColor( color );
}

对于您的问题,我有一个非常快速简单的快速修复方法。在调用 target.draw(aim, states); :

之前,只需将这行代码添加到可点击 class 的 draw 成员函数中
aim.setFillColor(this->getFillColor());

像这样:

virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const {
    aim.setFillColor(this->getFillColor());
    target.draw(aim, states);
}

或者您可以同时重载 setFillColorgetFillColor 成员函数:

void setFillColor(const sf::Color& c) {
    aim.setFillColor(c);
}

const sf::Color& getFillColor() {
    return aim.getFillColor();
}

解释:

您这样声明了一个变量 stuffclickable<sf::Text> stuff(mouse, objects[0]);

根据您的模板 class 定义,这意味着东西是 clickable 继承自 sf::Text,因此它是 clickable sf::Text,它是还有一个sf::Text.

正在查看您 clickable class 的字段:

  • 一个sf::Vector2i mouse;
  • a object& aim;,目标是 object 类型的 reference,其中 object 是您的模板参数

因此,您的变量 stuff 包含 sf::Text 对象将包含的所有数据,因为东西是 sf::Textsf::Vector2i 和对一个 sf::Text 对象,不是他自己。所以在这里,你的东西对象可以访问 2 个不同的 sf::Text 对象。他自己和目标引用的人。

draw成员函数代码显示它绘制字段aim,所以引用的是sf::Text,而不是自己持有的数据

当您在代码中这样做时

objects[0].setFillColor( sf::Color::Red );

您在 stuff 对象的 aim 字段引用的对象上调用 setFillColor 方法,而 :

stuff.setFillColor(sf::Color::Red);

更改 stuff 对象本身。并且您的绘制函数将绘制对象 引用 的东西对象,但不知道应用到东西对象的所有修改

所以解决方案很简单:应用于您的 stuff 对象的所有修改都需要应用于引用的对象

当您想要绘制对象时(在 draw 方法中)或当您要求应用修改时(例如当您调用 setFillColor 方法时),您可以这样做。

顺便说一句,Alex 是对的,您的 class 设计得不是很好。您也可以不保留对 sf::Text 对象的引用并为 (*this) 调用 sf::Text draw 方法(或者只是不要在可点击对象中重载 draw 方法并正确复制 sf::Text 在你的对象中 )

谢谢两位,我明白了!两种解释都很好。我重新设计了 class,对于以下卡住的程序员,这里是我的解决方案:

template <class object>
class clickable: public object{
public:
    clickable(const string& s, const sf::Font& f, unsigned int size) : object::Text(s, f, size) {}

    void cmd_out() {
        cout << (string) (*this).getString();
    }
    void graph_out(float x = 0, float y = 0) {
    }
    bool onMouseOver(const sf::Vector2i& eger) {    
        float width = (*this).getLocalBounds().width;
        float height = (*this).getLocalBounds().height;
        if ((eger.x >= (*this).getPosition().x) && (eger.x <= (*this).getPosition().x + width) && (eger.y >= (*this).getPosition().y) && (eger.y <= (*this).getPosition().y + height))
            return true;
        else return false;
    }
};

现在它可以工作了,但我只能用这个 sf::Text 可点击对象制作,但如果我需要任何其他对象,可以很容易地添加另一个基于所需的构造器。