2014-01-22 45 views
2

我正在製作Label和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; 

最後,一個包含Button本身的文件:

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 *和std :: shared_ptr的,但沒有成功

我的問題是,當我打電話ButtonManager ::平局(someSFMLWindow),當它試圖調用A->繪製(目標),它將寫入到控制檯:

R6025 - 純虛函數調用

並且當我在調試代碼,錯誤出現時按鈕的第一行: :繪製被調用(window.draw(buttonImage ))。

問題在哪裏?問題出在哪裏?

+1

爲什麼不直接在ButtonManager類中實現'sf :: Drawable :: draw'? – jready

+0

我沒有看到你想如何適應它,因爲你知道,我可以通過向量並在主要手動繪製,但我想自動化的東西,所以你只需調用ButtonManager :: draw(window)和它繪製所有按鈕創建編輯:我試過了,不認爲我沒有 – Creris

+0

如果你在ButtonManager中實現'sf :: Drawable :: draw',那麼你可以從任何地方'sf :: RenderWindow :: draw' ButtonManager對象。在一個SFML應用程序中,如何繪製其他所有內容,這一定會更加統一。 你是如何嘗試這樣做的,它不起作用?如果你只是從ButtonManager擴展'sf :: Drawable',你不應該有任何問題 – jready

回答

2

遍佈整個地方使用靜態通常會顯示糟糕的設計選擇。靜態成員變量基本上是突破所有「狀態」的全局變量。我不會詳細討論爲什麼應該避免使用全局變量,但是圍繞這個主題有足夠的線索,所以我相信你會找到一些東西。我也沒有說靜態函數在C++中沒有自己的位置,它只是使用'static'來避免以封裝的方式處理對象的煩惱,這不是一個真正的解決方案。

正如評論中所建議的那樣,通過從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; 
} 

當然你需要以及添加功能部件的創建和刪除的管理可見性(是什麼顯示盈/後面另一個小部件)。您可以爲某些小部件創建靜態創建工廠函數,但除此之外,您不應該創建靜態函數,而應該考慮設計以及如何減少類依賴關係並防止「注入WidgetManager無處不在」綜合症。

+0

雖然它不回答爲什麼純虛函數調用(既沒有評論),但它是非常好的解決我的問題,甚至比我已經達到了 – Creris

+0

啊對了,關於錯誤,它意味着那就是你想要調用純虛函數的基類的繪圖函數。在沒有代碼的情況下,很難說出類的用途。 – Lukas