2010-09-06 145 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