2017-08-24 86 views
0

我有一個設計問題,我試圖克服。讓我們假設類的結構和層次是正確的,我不能改變它。使用模板創建子類

我有一個名爲BaseWidget的類。它具有內部嵌套類Grid和Square。網格維護一個正方形的矢量。他們在那裏更好地組織繪圖行爲。 BaseWidget在其Layout()方法中構造Grid和Squares的向量。

現在我有了類DerivedWidget的Sub-classs BaseWidget。派生窗口小部件對BaseWidget :: Square類有額外的繪圖要求。因此,使用Derived :: WidgetSquare對BaseWidget :: Square進行子類化將會很好也很容易。

問題來自網格和正方形在BaseWidget :: OnLayout中構造的事實。所以當創建正方形網格矢量時,我想說「在你正在填充的矢量中使用DerivedSquare而不是Square」。

我相信我的解決方案是使用模板,但我不確定使用哪些模板。

class BaseWidget : public Widget 
{ 
    protected: 
     void Layout(void) 
     void Draw(canvas c); 

     class Square { 
      Square(Rect r) : region(r) {} 
      Rect region; 
      virtual void Draw(canvas c); 
     }; 

     class Grid { 
      std::std::vector<shared_ptr<<Square>> squares; 
      Rect region; 
      void Draw(canvas c); 
     }; 

     std::vector<Grid> m_grids; 
}; 

void Parent::Layout { 
    m_grids.resize(num_grids); 

    for (int i=0; i<num_grids; ++i) { 

     m_grids[i].region = some_rect; 

     for (int j=0; j<num_squares; ++j) { 
      m_grids[i].m_squares.push_back(std::make_shared<Square>(some_other_rect)); 
     } 
    } 
} 

void BaseWidget::Draw(Canvas c) 
{ 
    for (int i = 0; i < m_grids.size(); i++) { 
     m_grids.Draw(c); 
    } 
} 

void Grid::Draw(Canvas c) 
{ 
    // draw some stuff here 
    for (int i = 0; i < m_squares.size(); i++) { 
     m_squares[i].Draw(c); 
    } 
} 

void Square::Draw(Canvas c) 
{ 
    // draw some stuff here 
} 



// new class that extends parent 
class DerivedWidget : public BaseWidget 
{ 
    protected: 

     /* 
     * This class wants to do some special drawing in addition to its parents drawing 
     */ 
     class DerivedSquare : public Square { 
      virtual void Draw(canvas c); 
     }; 
} 
+0

您可以將DerivedWidget中的Square作爲成員類型,並且還可以將DerivedWidget作爲BaseWidget的模板參數 – gmoshkin

回答

1

如果我正確理解你的問題,你正在尋找像下面這樣的東西。請注意,我簡化了類和方法,它應該只是概念證明:

struct BaseWidget 
{ 
    struct BaseSquare 
    { 
     virtual void draw() 
     { 
      // ... Drawing Logic for Base Square 
     } 
    }; 

    virtual void draw() 
    { 
     drawInternal<BaseSquare>(); 
    } 

protected: 

    template <typename SquareType> 
    void drawInternal() 
    { 
     auto squareToDraw = std::make_shared<SquareType>(); 
     squareToDraw->draw(); 
    } 
}; 

struct DerivedWidget : BaseWidget 
{ 
    struct DerivedSquare : BaseSquare 
    { 
     virtual void draw() override 
     { 
      // Drawing Logic for Dervied Square 
     } 
    }; 

    virtual void draw() override 
    { 
     drawInternal<DerivedSquare>(); 
    } 
}; 

當然這有一些重要的限制。其中之一,BaseWidget類必須知道如何構造方塊,所以DerivedSquare不能有花哨的構造函數。您也可以通過將構造函數參數傳遞給drawInternal函數來克服這個問題,但我不確定這是否適合您的設計。

0

嘗試這樣:

template <class Derived> 
class BaseWidget : public Widget 
{ 
    // ... 
    class Grid { 
     std::std::vector<shared_ptr<<Derived::SquareType>> squares; 
     // ... 
    } 
} 

class DerivedWidget : public BaseWidget 
{ 
    using SquareType = DerivedSquare; 
    // ... 
} 
1

看來你只需要一個工廠,你可以爲添加一個虛擬方法:

class BaseWidget : public Widget 
{ 
protected: 
    void Layout() 
    void Draw(canvas c); 

    class Square { 
    public: 
     Square(Rect r) : region(r) {} 
     Rect region; 
     virtual void Draw(canvas c); 
    }; 

    class Grid { 
    public: 
     std::std::vector<shared_ptr<<Square>> squares; 
     Rect region; 
     void Draw(canvas c); 
    }; 

    virtual std::unique_ptr<Square> MakeSquare() const { return std::make_unique<Square>(/*...*/); } 


    std::vector<Grid> m_grids; 
}; 

// new class that extends parent 
class DerivedWidget : public BaseWidget 
{ 
protected: 

    /* 
    * This class wants to do some special drawing in addition to its parents drawing 
    */ 
    class DerivedSquare : public Square { 
     virtual void Draw(canvas c); 
    }; 


    std::unique_ptr<Square> MakeSquare() const override { return std::make_unique<DerivedSquare>(/*...*/); } 
} 

而且在代碼中使用MakeSquare()而不是硬編碼Square