嵌入式C ++ - 多态性和继承 [英] Embedded C++ - polymorphism and inheritance

查看:88
本文介绍了嵌入式C ++ - 多态性和继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Arduino上写一个游戏(空间入侵者),它连接到一个图形LCD,我有一个sprite类。这个类有诸如Player / Alien,位图对象,位置(x,y)和如何移动函数的属性。

I'm writing a game (space invaders) on an Arduino which is connected to a graphical LCD, and I have a sprite class. This class has attributes such as Player/Alien, a bitmap object, location(x,y), and a how to move function.

我想让每个实例有一个导弹,我认为这可以通过继承和多态性来完成,虽然我不确定如何 - 我精简的代码在下面,并给出一个更好的想法,我已经包括一个字形图像的形状。我想导弹从sprite类派生位置(x,y),但它会有自己的位图和移动方法,像(?)

I want each instance to have a missile and I think this may be done by inheritance and polymorphism, though I'm unsure how -- my streamlined code is below and to give a better idea as to shapes I've included a glyph image. I'd like Missile to derive location(x,y) from the sprite class, but it'll have its own bitmap and method of movement, something like(?)

Class Missile: public Sprite{
  Missile();   // create shape here
  void Move(); // has its own method of moving, but starts from Sprite(x,y)  
};  

[无论如何做,我想使用继承和多态性为我的C + +实践请]

[Regardless of how to do this, I'd like to use inheritance and polymorphism for my C++ practice please]

Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
unsigned char spaceShip[5]    PROGMEM = {0x3c, 0x1e, 0x1f, 0x1e, 0x3c};
unsigned char spaceAlien[5]   PROGMEM = {0x1e, 0x0f, 0x1f, 0x0f, 0x1e};
unsigned char spaceMissile[5] PROGMEM = {0x00, 0x00, 0x1f, 0x00, 0x00}; 

enum TYPES {ALIEN = 0, PLAYER = 1 };
class Sprite
{
  public:
    Sprite(TYPES Type);
    void Move();
    void Render()      { display.drawBitmap(x,y, spacePtr, 5, 6, BLACK); }
  private:
    unsigned char *spacePtr;
    unsigned int x, y;
    TYPES Type;
};

Sprite::Sprite(TYPES theType)
{
  Type   = theType;
  switch( Type )
  {
      case( PLAYER ):
        spacePtr = &spaceShip[0];
        x = xPlayer(); // get x from xfunction
        y = yPlayer(); // get y from yfunction
        break;      
      case( ALIEN ):
        spacePtr = &spaceAlien[0];
        x = random(0, 82);
        y = random(10, 20);
        break;
      default: 
        break;
   }
}

推荐答案

意识到你当前实现的sprite实际上可以分为(至少)三个类:A Player,Alien和Sprite,前两者派生。

Before getting the missile involved, you should realize that your current implementation of sprite could in fact be split into (at least) three classes: A Player, an Alien and a Sprite from which the former two derive.

继承点是它代表一个is a关系。也就是说,玩家是雪碧,外星人是雪碧。在这种情况下,sprite是可以移动,渲染,具有位置和位图的类。当你在那里显示它,区别外星人和播放器的东西是它的初始位置它的位图数据的位置和大概是它的移动方式。

The point of inheritance is that it represents a "is a" relationship. I.e.: a Player IS A Sprite, an Alien IS A Sprite. In this case, a sprite is a class that can be moved, rendered, has a position and a bitmap. As you show it there, the things that distinguish an Alien from a Player is its initial position the location of its bitmap data and presumably the way it moves.


class Sprite
{
  public:
    virtual ~Sprite();
    Sprite(unsigned char * const spacePtrIn, unsigned int xInit, unsigned int yInit)
        : spacePtr(spacePtrIn)
        , x(xInit)
        , y(yInit)
    {}
    virtual void Move() = 0;
    void Render(Display &display) const { display.drawBitmap(x,y, spacePtr, 5, 6, BLACK); }
    unsigned int X() const {return x;} 
    unsigned int Y() const {return y;}
  protected:
    void X(int newX) { x = newX; }
    void Y(int newY) { y = newY; }
  private:
    unsigned char * const spacePtr;
    unsigned int x, y;
};

class Alien : public Sprite
{
public:
   Alien()
     : Sprite(spaceAlien, random(0, 82), random(10, 20))
   {}
   virtual void Move();
};

class Player : public Sprite
{
public:
   Player()
     : Sprite(spaceShip, xPlayer(), yPlayer())
   {}
   virtual void Move();
};

一旦我们将玩家和外星人的特殊属性与Sprite的一般属性分离,它应该会更清晰如何导弹与一个精灵相关:它是一个。

Once we have separated the specialized properties of players and aliens from the general properties of a Sprite, it should make it clearer how a missile relates to a sprite: It IS one.


class Missile : public Sprite
{
public:
   Missile(Sprite const &launchPoint)
     : Sprite(spaceMissile, launchPoint.X(), launchPoint.Y())
   {}
   virtual void Move();
};

这个假设是,一旦导弹从指定的Sprite发出,它没有什么进一步。注意,导弹和外星人/玩家之间没有依赖关系。

The assumption is that once the missile originates from the specified Sprite it has nothing further to do with it. Note that there is no dependency between Missiles and Aliens/Players.

其他需要注意的一点是,Sprite的x和y属性只能由sub-类通过受保护的setter函数,让Sprite类进行范围检查和/或如果需要以不同的格式存储值 - 这是工作时的封装原理。此外,我已经删除了对一个可能的全局显示对象的引用,而是在需要时传递到现在的const Render函数。这是有好处的一大堆原因,尤其是全局的一般邪恶和它们引入的隐藏的依赖。通过使函数const,调用者可以更容易地假设一旦函数返回,显示器将不会被该对象触摸,直到下一次调用。这样做的开销可能非常低,所以你在Arduino上做的事实不应该阻止你,同样使用getter / setter函数,因为编译器很可能会优化它们。

Other points to note is that the x and y attributes of the Sprite can only be modified by the sub-classes through protected setter functions, leaving the Sprite class to range check and/or store the values in a different format if it desires - this is the principle of encapsulation at work. Also, I have removed the reference to a presumably global display object - instead it is passed into the now const Render function when required. This is good for a raft of reasons, not least the general evilness of globals and the hidden dependencies they introduce. By making the function const, the caller can more readily assume that once the function returns, the display will not be touched by that object until the next call. The overhead of doing this is likely to be very low so the fact you are doing it on an Arduino shouldn't deter you, likewise with getter/setter functions as the compiler will most likely optimize them away.

多态性进入这里是因为调用Render和Move方法的代码不需要知道它处理的对象的实际类型是为了这样做 - 它需要知道的是sprites。

Polymorphism comes into this because the code invoking the Render and Move methods doesn't need to know what the actual type of the objects it's dealing are in order to do so - all it needs to know about are sprites.


void MoveAndRender(Sprite **begin, Sprite **end, Display &display) 
{
   for(; begin != end; ++begin)
   {
      (*begin)->Move();
      (*begin)->Render(display);
   }
}

当然,有无数种方法来解决这个问题,首先定义问题。这只是一个演示如何继承可能适合您的方案。

Of course there are an infinite number of ways of tackling this problem and the hardest bit is defining the problem in the first place. This is just a demonstration of how inheritance might fit your scenario.

继承只是多种OO关系中的一种,并且经常被过度使用或滥用,导致一些真正可怕的代码。熟悉组合(有a),聚合(共享a)和关联(知道a?)。

Inheritance is only one of a number of OO relationships and is often overused or misused, resulting some truly hideous code. Familiarize yourself with composition ("has a"), aggregation ("shares a"), and association ("knows a"?) as well. Often a mix of inheritance and composition is far more effective than inheritance alone (see Bridge pattern, Proxy pattern and friends.)

编辑已移除了所有的继承和组合, Type属性,因为实际的对象类型应该是表征其行为所需要的 - 这是点,真的。添加了MoveAndRender示例。

Edit Removed the Type attribute since the actual object type should be all that is needed to characterize its behaviour - this is point, really. Added MoveAndRender example.

这篇关于嵌入式C ++ - 多态性和继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆