在父类中访问子类的函数

时间:2013-12-03 14:42:48

标签: c++ inheritance

我一直在编写一个简单的棋盘游戏,以便在实践中学习C ++的概念。我已经实现了它:它由tile组成,每个tile都是一个继承自父类的子类。该板是一个具有瓦片矢量的类。

有几种瓷砖。其中一些可以由玩家购买。有几种不同类型的可购买的瓷砖以及不同的属性,所以我认为为可以购买的瓷砖制作基础类TileOnSale并制作实际类型的子类是可爱的,其中两个我在下面的代码中提供

现在我的问题是如何访问未在父类(TileOnSale)中定义的子成员函数? Board使用各种不同的tile进行初始化,因此我可以使用getTile(int location)函数从那里提取Tile。但是,这被解释为仅仅是Tile,而不是TileOnSale或StreetTile。我知道无法通过这种方式掌握StreetTile的buildHouses功能。

那么,是否有一种强大的,甚至更好的方法呢?我可以制作模板或其他东西来保存可能是StreetTiles或StationTiles的Tile对象或其他类似的Tile吗? 或者我应该重新设计类结构?

这是一个简单的代码。我试图只提供理解问题所需的内容。此外,最初的Tile和Board都在他们自己的头文件中。我决定没有必要向Player类显示拥有TileOnSale对象的向量,但是它保留了与Board完全相同的访问问题。

// Board.h
#include "Tile.h"
typedef vector<Tile> Tiles;

class Board
{
public:
    Board();
    ~Board();
    Tile            getTile(int location);
private:
    Tiles           tiles;
};

// Tile.h
class Tile
{
public:
    Tile();
    ~Tile();
protected:
    tileType    tile_type; // this is enum containing unique type
    string      description;
};

class TileOnSale : public Tile
{
public:
    TileOnSale();
    ~TileOnSale();

    virtual int getRent() const { return 0; };
};

class StreetTile : public TileOnSale 
{
public:
    StreetTile();
    ~StreetTile();
    int getRent() override;
    void buildHouses(int number);
private:
    int houses;
};

class StationTile : public TileOnSale
{
public:
    StationTile();
    ~StationTile();
    int getRent() override;
};

编辑:为代码添加了可能澄清的评论。

2 个答案:

答案 0 :(得分:2)

您可能需要查看visitor pattern

  

从本质上讲,访问者可以在不修改类本身的情况下向一个类族添加新的虚函数;相反,我们创建了一个访问者类,它实现了虚函数的所有适当的特化。访问者将实例引用作为输入,并通过双重调度实现目标。

双重调度意味着您实际上正在调用虚拟函数两次:首先是主题,然后以多态方式调用访问者。

在您的情况下,只有一种方法,即建造房屋,但您可能希望稍后添加其他方法(例如在屏幕上绘制它们)。鉴于您当前的示例,您应该将此方法添加到Tile和StreetTile:

virtual void accept(Visitor& v) { v.visit(*this); }

这是访客基类实现:

class Visitor {
public:
    virtual void accept(Tile& t) = 0;
    virtual void accept(StreetTile& t) = 0;
};

之后,您可以实现Builder类:

class Builder: public Visitor {
private:
    int numberOfHouses;
public:
    Builder(int n): numberOfHouses(n) {}
    virtual void accept(Tile& t) {}
    virtual void accept(StreetTile& t) {
        t.buildHouses(numberOfHouses);
    }
};

之后你要做的就是构建这样一个构建器,并在你的tile矢量中的每个tile上调用它:

Builder b(10);
for (Tile tile : tiles) {
    tile.accept(b);
}

答案 1 :(得分:1)

一种简单的方法是为每种类型添加唯一的id(枚举或字符串)。播放器类可以询问类型(在基类中定义)并相应地转换为派生类。

由于它需要在派生(例如专门)类上调用函数,因此它具有执行强制转换的知识。

具有类型ID也非常适合调试。