2010-09-06 150 views
0

我對模板的實際使用頗爲陌生,所以我有以下設計問題。從一個抽象基類Bunch派生模板化基類中的派生類

我設計類Bunch2dBunch4d

class Bunch {virtual void create()=0;}; 
class Bunch2d : public Bunch {void create();}; 
class Bunch4d : public Bunch {void create();}; 

Bunch將包含一個容器,一個dequevector(見this question: Choice of the most performant container (array))的Particle的:

typedef Blitz::TinyVector<double,DIMENSIONS> Particle; 

因此,您看到我的問題:Bunch必須包含此容器,因爲在我的一堆「基本」操作是「維獨立」(如「容器的大小」,「清除容器」等),所以我認爲該容器屬於基類(「Bunch」有一個'容器)。

但是這個容器必須知道派生類的尺寸(2或4)。

所以我的想法是用一個模板基類來給typedef的容器的正確尺寸:

enum Dimensions {TwoDimensions = 2, FourDimensions = 4, SixDimensions = 6}; 
template<Dimensions D> class Bunch 
{ 
    protected: 
    typedef Blitz::TinyVector<double,D> Particle; 
    std::deque<Particle> particles_store; 
    public: 
    virtual void create() = 0; 
    virtual ~Bunch(); 
}; 

class Bunch2d : public Bunch<TwoDimensions> 
{ 
    public: 
    ~Bunch2d(); 
    void create(); 
}; 

class Bunch4d : public Bunch<FourDimensions> 
{ 
    public: 
    ~Bunch4d(); 
    void create(); 
}; 

你能給我你的意見對這個設計?它會正確使用模板嗎?面向對象概念的有效性如何?用模板化的基類?

感謝您的幫助/回答/意見。

+0

不確定你的層次結構......在現實生活中,2D空間將是4D空間的特例,這是6D空間的一個特例。 – 2010-09-06 09:08:00

+1

如果我在2d的情況下,我不想攜帶我的6維TinyVector例如。 – 2010-09-06 09:24:48

回答

2

有一個單一的說明:不同的模板實例(即參數中具有不同類型的模板類)具有不同的類型,因此不是單個基類。

如果你需要多態,你需要在你的設計中增加了一層:

class Bunch 
{ 
public: 
    virtual void create() = 0; 
    virtual ~Bunch(); 
}; 

template <Dimensions D> 
class TBunch: public Bunch 
{ 
private: 
    typedef Blitz::TinyVector<double,D> Particle; 
    std::deque<Particle> mParticles; 
}; 

class Bunch2d : public TBunch<TwoDimensions> 
{ 
public: 
    ~Bunch2d(); 
    void create(); 
}; 

在另一方面:protected應該被禁止的屬性。

這個問題是耦合問題之一,因爲protected將屬性/方法暴露給未知數量的類,它與public沒有什麼不同,因爲不可能說明有多少方法會受到實現更改的影響。

對於方法,這是可以接受的,因爲方法可以保持向後兼容(有時以某些技巧/等等爲代價)。

對於屬性,這是不可接受的,因爲屬性是實現細節,而不是接口,並且更改不能向後兼容。

因此,我強烈建議您不要使用protected作爲屬性。在這種特殊情況下,最好將模板類中的訪問分解爲mParticles,而不公開底層實現。

小提示:如果您不能在dequevector之間切換,而不會超出擁有它們的類別,那麼您有設計問題。

+0

但問題是容器中包含的「粒子」(包含數百萬個元素)必須由派生類操縱,並且將它設爲私有並不是一個好主意,然後訪問每個元素一。或者我可以使用函數指針或函數對象,並將它提供給TBunch,在TBunch中,方法將遍歷元素並將函數應用於它們。它可以保持私密性。這是個好主意嗎? – 2010-09-06 09:29:33

+1

完全可以接受使用函數指針或謂詞和'TBunch :: foreach'方法,是的。我不建議隱藏使用「粒子」的事實,只是爲了隱藏你如何存儲它們,這是一個實現細節。你也可以提供一個'ParticleIterator',封裝'std :: deque :: iterator'。 Boost.Iterator提供了諸如iterator_adaptor和iterator_facade之類的工具。 – 2010-09-06 10:00:02

2

然後,您會失去在運行時將Bunch類的指針指向Bunch2d或Bunch4d對象並通過該指針多態操縱這些對象的能力。如果您不要忽略這一點很重要,請勿使基類模板化。否則,根本沒有虛擬函數和抽象基類在這裏,所以我建議只使用模板。

0

就開始而言,就繼承而言,Bunch<TwoDimensions>Bunch<FourDimensions>是完全無關的類。因此,Bunch2dBunch4d沒有共同的基類!

如果這會對您造成問題,您將不得不廢除模板,並在運行時參數化DIMENSIONS