gpt4 book ai didi

c++ - 嵌入式C++——多态与继承

转载 作者:行者123 更新时间:2023-11-30 04:13:50 26 4
gpt4 key购买 nike

我正在一个连接到图形 LCD 的 Arduino 上编写一个游戏(太空入侵者),并且我有一个 sprite 类。此类具有 Player/Alien、位图对象、location(x,y) 和如何移动函数等属性。

我希望每个实例都有一个导弹,我认为这可以通过继承和多态性来完成,尽管我不确定如何——我的简化代码在下面,为了更好地了解形状我已经包含了一个字形图像。我希望 Missile 从 sprite 类派生 location(x,y),但它会有自己的位图和移动方法,类似于 (?)

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

[不管怎么做,我都想在我的C++实践中使用继承和多态]

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;
}
}

bitmaps here

最佳答案

在涉及导弹之前,您应该意识到您当前的 sprite 实现实际上可以分为(至少)三个类:Player、Alien 和前两者派生的 Sprite。

继承的要点在于它代表了一种"is"的关系。即:玩家是 Sprite ,外星人是 Sprite 。在这种情况下, Sprite 是一个可以移动、渲染、具有位置和位图的类。正如您在那里展示的那样,区分外星人和玩家的是它的初始位置、位图数据的位置以及它的移动方式。

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 的一般属性分开,它应该更清楚导弹与 Sprite 的关系:它是一个。

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

假设一旦导弹从指定的 Sprite 发出,它就不再与它有任何关系。请注意,导弹和外星人/玩家之间没有依赖关系。

其他需要注意的是,Sprite 的 x 和 y 属性只能由子类通过 protected setter 函数修改,如果 Sprite 类需要进行范围检查和/或以不同的格式存储值欲望——这是工作中的封装原则。此外,我已经删除了对可能是全局显示对象的引用——而是在需要时将其传递到现在的 const Render 函数中。这有很多原因,尤其是全局变量的普遍邪恶和它们引入的隐藏依赖项。通过将函数设置为 const,调用者可以更容易地假设一旦函数返回,直到下一次调用之前该对象不会触及显示。执行此操作的开销可能非常低,因此您在 Arduino 上执行此操作的事实不应阻止您,同样使用 getter/setter 函数,因为编译器很可能会优化它们。

之所以出现多态性,是因为调用 Render 和 Move 方法的代码不需要知道它正在处理的对象的实际类型是什么 - 它需要知道的只是 Sprite 。

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

当然,解决这个问题的方法有无数种,最难的是首先定义问题。这只是继承如何适合您的场景的演示。

继承只是许多 OO 关系中的一种,并且经常被过度使用或误用,从而导致一些真正可怕的代码。熟悉组合(“有一个”)、聚合(“共享一个”)和关联(“知道一个”?)。继承和组合的组合通常比单独继承更有效(请参阅桥接模式、代理模式和 friend 。)

编辑 删除了 Type 属性,因为实际的对象类型应该是表征其行为所需的全部 - 这一点,真的。添加了 MoveAndRender 示例。

关于c++ - 嵌入式C++——多态与继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19191438/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com