2

我遇到了一个让我觉得很愚蠢的问题。在一个爱好项目中,我有一个指向接口类的指针的 std::list,它指向所述接口的各种具体实现。

例如,假设我有以下内容:

class Seafood ...
class Fishstick : public Seafood ...
class Squid : public Seafood ...
...
std::list<Seafood*> buffet;

现在我的自助餐里有不同的海鲜,我想计算一下我有多少鱼条,看看是否需要从厨房订购更多。

如果没有 RTTI 或其一些不正当的实现,我将如何做到这一点?我读过一些文章声称如果您发现自己想要使用 RTTI,那么您正在以错误的方式接近 OOP 和/或您的解决方案应该重新设计。是否有一些模式或其他解决方案可以解决这个问题?我敢肯定,以前曾多次浮出水面。

我在想很明显这是某种虚函数,但是如果不构建俗气的 RTTI 版本或有关接口中后代的一些知识(CountIfFishstick / IsFishstick / Is(type)),我无法弄清楚如何做到这一点)。

编辑:想到的另一件事是保留一份鱼竿列表,一份鱿鱼列表等。但这肯定会破坏界面/实现的整个目的。

4

6 回答 6

3

您可能想要访问者模式的一些变体。有很多,很难说你想要哪个。我可能会推荐获得Modern C++ Design并查看 Alexendrescu 的实现。否则,谷歌“访问者模式”,你会得到 1000 公里的链接来阅读。

于 2012-05-25T18:25:28.617 回答
1

复合模式怎么样?自助餐真的是海鲜系列的集合。FishStick 和 Squid 是 Composite 模式中的“组件”,它们将保持其项目数。所以当 Buffet 是 list 时,它可以遍历和调用 Composites 上的 count。

于 2012-05-26T07:56:14.430 回答
1

访客模式是您正在寻找的。还有一个特殊版本的访问者,称为非循环访问者,它使用 RTTI 来解决原始访问者的一些问题,所以 RTTI 并不总是错误的,但除非你真的知道自己在做什么,否则它导致可怕的代码。 .

于 2012-05-25T18:28:54.273 回答
1

大概你name在基类中有一个函数来返回项目的名称,这样你就可以把它展示给厨房了。只需使用它来索引项目计数地图。

通常,您可以提供一个函数,该函数返回每个类的任何唯一标识符。

于 2012-05-25T19:18:12.500 回答
0

如果您使用的是 C++11,您可以执行以下操作:

int num_fish_sticks = std::count_if(buffer.begin(), buffet.end(),
    [](const SeaFood* sf) {sf->is_fish_stick()});

你需要在 SeaFood 中声明一个纯虚函数:

virtual bool is_fish_stick() const = 0;

并在子类中相应地实现它。

编辑:当然,如果您有太多子类,这可能会很混乱。在这种情况下,您最好只使用 RTTI:

int num_fish_sticks = std::count_if(buffer.begin(), buffet.end(),
    [](const SeaFood* sf) {typeid(*sf) == typeid(Fishstick)});
于 2012-05-25T18:38:20.773 回答
0

我认为您的问题比您想象的要基本得多:至少正如您所介绍的那样,似乎根本没有太多(任何?)理由在这里使用继承。

当您的对象具有不同的行为时,继承很有用,但在这种情况下,它们似乎都具有基本相同的行为——事实上,几乎没有任何行为(除非算作“装死”)。

如果我要为自助餐建模,我可能使用容器。热桌上的每个托盘都是一个容器,里面装着一些东西。如果需要,您可以将桌子建模为托盘容器,并且(可能)将房间建模为桌子容器。

每个托盘都有一个“食物”(或任何你喜欢的名字),你通常有一个名字和一个数量。唯一的行为可能是处理食物何时“供应”的计时器,并基于该计时器何时需要移除任何剩余的食物。您可能还有更多,例如将食物分为仅作为全餐一部分提供的食物,与仅购买沙拉吧的人提供的食物。

于 2012-05-25T18:45:05.670 回答