【问题标题】:Access child class' functions within parent class在父类中访问子类的功能
【发布时间】:2013-12-19 16:30:44
【问题描述】:

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

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

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

那么,有没有一种健壮的,甚至更好的简洁的方法来做到这一点?我可以制作一个模板或其他东西来保存可能是 StreetTiles 或 StationTiles 或其他 Tile 的 Tile 对象吗? 还是我应该重新设计类结构?

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

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

编辑:为代码添加了一个潜在的澄清注释。

【问题讨论】:

  • 不确定这是您想要的。不过看看stackoverflow.com/questions/14948957/…
  • 是的;这看起来像我的意图。谢谢,我知道有几种方法可以做到这一点。
  • 顺便说一句:你应该使用矢量
  • 第一条评论(来自 VusP)对我来说是非常有用的信息。虽然访问者模式已经解决了几个问题,但指针转换已经解决了其他几个问题。所以,感谢您指出这一点。

标签: c++ inheritance


【解决方案1】:

您可能想看看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);
    }
};

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

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

【讨论】:

  • 哇,我不知道这个,但它看起来很酷。我确实想添加更多方法(sellHouses 等),只显示一个,因为 buildHouses 足以解释这个想法。我去看看链接。
  • 还没有,因为我没有时间进一步研究它。不过,我想我会先尝试这种方法,因为它看起来很不错。
  • 我阅读了更多关于访问者模式的内容,虽然我还没有实现它,但它绝对是这里提出的完成我想要的最简洁的方式。此外,它很好地解决了另一个问题,即玩家到达某个板块。谢谢!
【解决方案2】:

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

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

有一个类型 ID 也很适合用于调试。

【讨论】:

  • 我想如果我为每个可能实际工作的返回类型实现一个函数,因为我有不到十种不同类型的子 Tile。不过,它不会那么整洁,它们中的代码几乎是相同的。 =) 另外,我已经为每个 Tile 指定了一个类型(枚举 tileType),尽管我似乎忘记了包含它的定义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-07
  • 2011-06-29
  • 1970-01-01
相关资源
最近更新 更多