2014-01-22 7 views
2

Im создание классов Label и Button. Ярлык в основном служит текстом, который прикреплен к Button, а Button имеет текстуру кнопки и еще несколько вещей.SFML C++ рисование в RenderWindow чистой виртуальной функции сбой выполнения

Я хотел автоматизировать вещи, поэтому вам не нужно вызывать метод рисования каждой кнопки отдельно, поэтому я создал класс ButtonManager, у которого есть вектор и статическая функция члена-члена.

Проблема заключается в том, что вектор содержит класс интерфейса, а не обычный (для будущих расширений типов кнопок).

Перед тем, как описать проблему, позволяет увидеть код:

Файл с основным интерфейсом для всех кнопок:

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 ВТН ButtonBase * и станд :: shared_ptr, без успеха

У меня есть проблема в том, что, когда я называю ButtonManager :: Жеребьевка (someSFMLWindow), когда он пытается вызвать a-> рисуем (цель), он будет писать в консоль:

R6025 - Вызов чисто виртуальной функции

и когда я отладки кода, появилась ошибка, когда первая строка кнопки: : draw был вызван (window.draw (buttonImage)).

Где проблема? какие-либо намеки, где проблема?

+1

Почему бы не просто реализовать 'sf :: Drawable :: draw' в классе ButtonManager? – jready

+0

Я не вижу, как бы вы хотели поместить его, потому что вы знаете, я мог бы просто перевернуть вектор и нарисовать вручную в основном, но я хочу автоматизировать все, поэтому вы просто вызываете ButtonManager :: draw (window) и его рисует все созданные кнопки edit: я пробовал, не думаю, что я не сделал – Creris

+0

Если вы реализуете 'sf :: Drawable :: draw' в ButtonManager, вы можете' sf :: RenderWindow :: рисовать 'объект ButtonManager откуда угодно. Это определенно будет более однородным с тем, как все остальное делается в приложении SFML. Как вы пытались это сделать, и это не сработало? Если вы просто расширяете 'sf :: Drawable' из ButtonManager, у вас не должно быть проблем – jready

ответ

2

Использование статического по всему месту часто показывает неправильный выбор дизайна. Статические переменные-члены являются, по существу, глобальными, которые прорывают все «состояния». Я не буду вдаваться в подробности, почему нужно избегать глобальных движений, но вокруг этой темы достаточно потоков, поэтому я уверен, что вы что-то найдете. Я также не говорю, что статические функции не имеют своего места в 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; 
} 

Конечно, вы должны добавить функции для создания и удаления виджетов, а также управлять видимостью (что показывает Infront/позади другого виджета). Вы можете создавать фабричные функции статического создания для определенных виджетов, но кроме этого, вы не должны создавать статические функции, а вместо этого подумайте о дизайне и о том, как уменьшить зависимости класса и предотвратить синдром «инжекционно-виджет-менеджер».

+0

, в то время как он не отвечает, почему вызов чистой виртуальной функции (также не комментарий), но это очень хорошее решение моей проблемы, и даже лучше, чем то, что я додумал до – Creris

+0

. А вот, об ошибке, это означает что где-то вы пытаетесь вызвать функцию draw базового класса, которая является чистой виртуальной. Где точно сказать без кода, где используются классы. – Lukas

Смежные вопросы