2014-01-26 116 views
0

我對問題標題不滿意,但我無法很好地描述它。爲了簡潔起見,我將這些實現放在類聲明中。在抽象基類中使用抽象類成員的最佳方法?

我有這樣一個類:

class VisibleObject { 
    public: 
    void draw(sf::RenderWindow& rw) { 
     rw.draw(*shape.get()); 
    } 
    virtual void setSize(sf::Vector2f) = 0; 

    protected: 
    std::shared_ptr<sf::Shape> shape; 
} 

sf::Shape是一個抽象類。然後,我有一個派生類,像這樣:

class Brick : VisibleObject { 
    Brick() { 
     shape.reset(new sf::RectangleShape()); 
    } 
    void setSize(sf::Vector2f newSize) { 
     std::dynamic_pointer_cast<sf::RectangleShape>(shapes).get()->setSize(newSize); 
    } 
} 

sf::RectangleShape()是一個具體的類,從sf::ShapesetSize()繼承了它的定義,不sf::Shape,這就是爲什麼我要投。

當然,如果動態轉換失敗並返回一個空的shared_ptr,我需要做一些錯誤處理。

我這樣做是因爲我想能夠定義draw方法一次,因爲在這個簡單的遊戲中,每個對象都會以這種方式繪製其成員。最初,我把這個形狀留在了基類之外,例如Brick只會擁有自己的專用sf::RectangleShape,可以在堆棧上實例化;這是乾淨的,但然後繪製方法必須重寫爲每個對象類型。

這種方法很有效,但更難以使用並引入了堆分配。我也有shared_ptr開銷(我會用unique_ptr,但我需要動態鑄造)。

這是做我想做的最合適的方式嗎?

回答

1

而是在std::shared_ptr<sf::Shape>強制存儲,爲什麼不簡單介紹一種從具體類中檢索sf::Shape&的方法?

class VisibleObject { 
    virtual sf::Shape& getShape() = 0; 
public: 
    void draw(sf::RenderWindow& rw) { 
     rw.draw(getShape()); 
    } 
    virtual void setSize(sf::Vector2f) = 0; 
}; 

class Brick : VisibleObject { 
    sf::RectangleShape shape; 
    sf::Shape& getShape() override { return shape; } 
public: 
    void setSize(sf::Vector2f newSize) override { 
     shape.setSize(newSize); 
    } 
}; 

看來可笑通過指針來保存基地,引進和間接性和向下轉換引用計數的開銷,當你可以只保存一個普通的老成員。事實上,如果我理解正確的問題,你很可能使用模板來生成具體類和避免了大量的樣板:

class VisibleObject { 
public: 
    virtual ~VisibleObject() {} 
    virtual void draw(sf::RenderWindow&) = 0; 
    virtual void setSize(sf::Vector2f) = 0; 
}; 

template <typename Shape> 
class VisibleConcreteObject : public VisibleObject { 
    Shape shape; 
public: 
    void draw(sf::RenderWindow& rw) override /* final? */ { 
     rw.draw(shape); 
    } 
    void setSize(sf::Vector2f newSize) override /* final? */ { 
     shape.setSize(newSize); 
    } 
}; 

typedef VisibleConcreteObject<sf::RectangleShape> Brick; 
+0

嘿,我是新手!實際上這是一個有吸引力的解決方案我避免了一個成員Shape的混亂,同時避免重複。謝謝。 – esel

+0

@esel還有另一種選擇,把我的答案和Kerrek的混合起來。 – Casey

1

您還沒有共享你正在嘗試做的一切,但是這是一個辦法:

template<ShapeT> 
class VisibleObject { 
public: 
    void draw(sf::RenderWindow& rw) { 
      rw.draw(*shape.get()); 
    } 
    virtual void setSize(sf::Vector2f) = 0; 

protected: 
    std::shared_ptr<ShapeT> shape; 
    void reset(ShapeT* shape) { 
     this->shape = shape; 
    } 
} 

class Brick : VisibleObject<sf::RectangleShape> { 
    Brick() { 
     shape.reset(new sf::RectangleShape()); 
    } 
    void setSize(sf::Vector2f newSize) { 
     shape->setSize(newSize); 
    } 
} 

可能有原因,這並不爲你工作,但沒有更深入的瞭解,我不能」猜猜看是什麼。

+0

這是堅實的,不過你說得對,我沒有給足夠的見解。我認爲,一旦我嘗試使用不同行爲的不同類型,就會崩潰。爲了知識的緣故,我能否創建一個包含指向'VisibleObject'的指針的映射,而不需要類型?像'map '? – esel

+0

我無法編輯我上面的評論。我遺漏了地圖上的指針星號。 'map '(當然,我會在練習中使用一個智能指針) – esel

+1

@esel,unfortuantely no。這確實是這種方法的缺點。你需要Kerrek的解決方案。 –

3

將接口保持爲接口可能更好,而不是開始強制實現細節。因此,只要有一個空基類,像這樣:

class VisibleObject 
{ 
public: 
    ~VisibleObject() {} 

    virtual void draw(sf::RenderWindow & window) = 0; 

    virtual void setSize(sf::Vector2f const & size) = 0; 
}; 

你能堅持形狀存儲爲實現該接口的具體類。

此外,Shape應該提供一個虛擬的大小調整方法:

class Shape 
{ 
public: 
    virtual ~Shape() {} 

    virtual void resize(sf::Vector2f const & size) = 0; 
}; 

現在你可以做,比如說,一個VisibleShapeObject作爲中間基類:

class VisibleShapeObject : public VisibleObject 
{ 
public: 
    virtual void draw(sf::RenderWindow & window) override final 
    { 
     window.draw(*shape_); 
    } 

    virtual void setSize(sf::Vector2f const & size) override final 
    { 
     shape_->resize(size); 
    } 
protected: 
    std::shared_ptr<Shape> shape_; // or unique_ptr<Shape> 
}; 
+0

關於這一點,我確實提到(不好),我開始採用這種方法;我只是試圖避免代碼重用爲每個派生類重寫通用方法(也希望學習),但看起來我應該堅持下去。 – esel

+0

至於第二部分,我不明白'resize'提供了什麼。它看起來並不像你在任何地方實現它,它看起來是多餘的,因爲'Shape'已經提供了設置其大小的方法。 – esel

+1

通過在'Shape'中聲明一個虛擬'resize()'成員,你不需要在'setSize()'中做任何類型轉換,就像調用任何其他虛擬方法一樣調用'resize()'並且讓多態做爲你工作。通過調用'resize()'抽象,這只是一個強制任何'Shape'後代實現'resize()'的實現細節。你可以簡單地在'Shape'中留下'resize()'非空抽象的實現,然後後代只有在真正需要時才能覆蓋它。 'setSize()'不會在乎任何方式。 –