我有一个带有一些继承者的抽象基类,我创建了一个指向继承者的抽象基类的指针数组:
抽象基类:
class Tile
{
public:
bool isPassable;
void setTileSet( SDL_Texture *Texture );
SDL_Rect* clip;
};
继承:
class Floor: public Tile
{
public:
bool isPassable = true;
SDL_Rect clip = { 20, 0, 20, 20 };
};
指针数组:
Tile * dungeon[ z ][ x ][ y ] = {{{ nullptr }}};
当我尝试通过指针数组访问成员SDL_Rect剪辑以blit一个tile时,没有任何反应。该程序编译并运行,但屏幕保持默认黑色:
dungeon[ 0 ][ 0 ][ 0 ] = &floor;
Draw::renderTexture( TILESET, REN, 0, 0, dungeon[ 0 ][ 0 ][ 0 ]->clip );
但是,当我只使用Floor类访问剪辑时,图像会很好地显示:
Draw::renderTexture( TILESET, REN, 0, 0, floor.clip );
我认为指针抽象基类可能没有加载,但是当我试图将代码写出去除掉它时:
SDL_Rect error = { 0, 0, 20, 20 };
if( dungeon[ 0 ][ 0 ][ 0 ] != nullptr )
{
Draw::renderTexture( TILESET, REN, 0, 0, dungeon[ 0 ][ 0 ][ 0 ]->clip );
}
else
{
Draw::renderTexture( TILESET, REN, 0, 0, &error );
}
屏幕仍为黑色。
这是Draw :: renderTexture函数,虽然我怀疑它是问题所在:
void Draw::renderTexture(SDL_Texture *texture, SDL_Renderer *render, int x, int y, SDL_Rect *clipping )
{
SDL_Rect destination;
destination.x = x;
destination.y = y;
destination.w = clipping->w;
destination.h = clipping->h;
SDL_RenderCopy( render, texture, clipping, &destination );
答案 0 :(得分:0)
您需要首先转换数组成员,以便它知道它正在查看哪个成员。目前,您有一个Tile
个实例数组,因此当您将dungeon[ 0 ][ 0 ][ 0 ]->clip
传递给渲染函数时,系统会假定您的意思是基类。
如果您将其更改为(Floor*)(dungeon[ 0 ][ 0 ][ 0 ])->clip
,则应该有效。
但是我会指出这看起来像一个非常糟糕的设计,可能是因为你还没有完全理解继承和多态,尽管你可能有一些理由按照你的方式去做。
我个人会将类更改为如下,首先是基类:
class Tile
{
public:
Tile() :
m_passable(true) {}
Tile(bool passable, SDL_Rect& clip) :
m_passable(passable),
m_clip(clip) {}
virtual ~Tile() {}
inline void SetTileSet(SDL_Texture *texture) { m_texture = texture; }
inline SDL_Texture* GetTileSet() { return m_texture; }
inline void SetClip(SDL_Rect& clip) { m_clip = clip; }
inline SDL_Rect& GetClip() { return m_clip; }
inline void SetPassable(bool passable) { m_passable = passable; }
inline bool IsPassable() { return m_passable; }
protected:
bool m_passable;
SDL_Rect m_clip;
SDL_Texture* m_texture;
private:
Tile(Tile const&) = delete;
Tile& operator=(Tile const&) = delete;
};
然后是继承类:
class Floor : public Tile
{
public:
Floor(bool passable, SDL_Rect& clip) :
Tile(passable, clip);
protected:
private:
Floor(Floor const&) = delete;
Floor& operator=(Floor const&) = delete;
};
然后,如果您想要新的Floor
实例,请执行以下操作:
SDL_Rect clip = { 0, 0, 20, 20 };
Floor* myFloor = new Floor(true, clip);
然后只需执行以下操作即可将其放入数组中:
dungeon[ 0 ][ 0 ][ 0 ] = (Tile*)myFloor;
最后,如果进行这些更改,则应通过引用传递渲染函数:
void Draw::renderTexture(SDL_Texture* texture, SDL_Renderer* render, int x, int y, SDL_Rect& clipping )
{
SDL_Rect destination = { x, y, clipping.w, clipping.h };
SDL_RenderCopy( render, texture, &clipping, &destination );
}
答案 1 :(得分:0)
在每个楼层,您都有两个版本的isPassable:Floor::isPassable
和Tile::isPassable
。一个是初始化而另一个不是。您还有两个版本的剪辑。 Floor::clip
未初始化,Tile::clip
未初始化。所以当你将你的地牢元素称为Tile时,它会自然地访问未初始化的元素和灾难性攻击。
您所说的代码if( dungeon[ 0 ][ 0 ][ 0 ] != nullptr )...
没有帮助,因为Tile::clip
不是空的;它没有初始化。
解决方法是消除isPassable并从Tile或Floor中剪辑,因此每个只有一个副本,并且无法访问错误的副本。
如果你想把它保存在Tile中,这些是需要解决的问题:
Floor () : Tile (true, 20, 0, 20, 20) {}
,