开发者

Design classes for "two-dimension"-like expansion by inheritance

I'd like to make two base classes (e.g. figure and move) with some children for each one(cube, sphere and so on for figure; shift, rotate, rescale and so on for moves). Initial number of figures and moves is unknown - it must be expandable. Each move should know how to move each figure, so having N figures and M moves means to have N*M function for them. (Adding a move requires creation of N functions for each already existing figure and adding figure requires creation of M functions for each already existing move).

The question is how to declare theese functions? For example, I'll have a class Set containing list of figures (aka vector) and I need to ask this class to move all the figures by i-th move. Probably set would have a method of

set::move_all (const move& ) 

and... well what next? The easiest idea is to create virtual method

class figure { 
    ...
    virtual void move_this (const move& ) 
    ...
}

to call开发者_JAVA百科 a virtual method move_figure

class figure_i: public figure {
    ...    
    virtual void move_this (const move& M)
       {M.move_figure(*this);
       }  
    ... 
}

class move {
    ...
    template <class T> virtual void move_figure (T&) const
    ...
}

and specialize it for each i-th move like this

template <> void shift::move_figure <cube> (cube& C)
    {
    }

and so on, but virtual templates are illegal.


You are making things more complicated than needed. You have a collection of objects (which you are calling figures) and a collection of actions (which you are calling moves). The obvious choice from an OOP perspective is to make the moves methods in your figures classes.

Update

Based on the comment below, you should be using a linear algebra library such as boost::ublas. There are others as well that you might want to look into such as Eigen (more or less shown below).

The basic idea is to abstract both the figures and the moves to generalize both so you don't have to rewrite the code for each possible combination. Thus, you would create a base class which looks something like:

template <typename T> class figure
{
    std::vector<Eigen::Vector3d<T> > point_list;
    ...

    void applyTransform(const Eigen::Affine3d<T>& src)
    {
       for (auto pt=point_list.begin(); pt != point_list.end(); pt++)
           (*pt) = src * (*pt);
    }
}

In this case, you define your point list based on the shape you are rendering. You can adjust meaning of the points in your derived classes to define specific geometric figures you're interested in. The Eigen::Affine3D class is used to define the transformations you want to apply. Eigen already has rotations and other affine transformations defined, so you should be able to reuse those.

You can also look into some specialized OpenGL or DirectX geometry classes which does all of this for you.


Well, my current solution is to use typeid/typeinfo to identify figure/move pair and call corresponding function (non-member) to move figure by this move from global object of map type like this

typedef pair<string, string> fm_pair_t;
typedef figure (*fm_act_f) (const figure& F, const move& M);
map<fm_pair_r, fm_act_f> global_fm_map;

class move {
   ...
   figure move_figure (const figure& F) const
     {map<fm_pair_r, fm_act_f>::const_iterator i = 
          global_fm_map.find (fm_pair_t(typeid(F).name(), typeid(*this).name()));
      if (i == global_fm_map.end()) return F;
      return i->second (F, *this);
     }
   ...
};

and somewhere

figure cube_shift (const figure& _F, const move& _M)
   {const cube& F = *dynamic_cast <const cube*> (&F);
    const shift& M = *dynamic_cast <const shift*> (&M);

    // act here with F and M like normal instances of cube and shift!

   };

and, of course

global_fm_map(typeid(cube).name(), typeid(shift).name()) = cube_shift;

so unlike case of using templates, everything is independent and well expandable.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜