C ++多态继承问题的优雅解决方案

时间:2018-10-13 20:10:06

标签: c++ inheritance polymorphism

想象一下我们正在使用的库有两个类Dog和Bowl

class Bowl;

class Dog
{
    Bowl* m_bowl;
};

class Bowl
{
    Dog* m_owner;
};

狗拥有一个指向与其关联的Bowl对象的指针。 Bowl还拥有一个指向其关联的Dog对象的指针。一切都好。我现在派生一个新类FancyDog,扩展了Dog的功能

class FancyDog : public Dog
{
     // Do the fancy dog stuff
};

一切都还不错,至少直到FancyDog需要用新的闪亮豪华碗代替无聊的旧普通碗为止。

class FancyBowl : public Bowl
{
    // Extra functions only relevant for FancyBowls
};

FancyDog应该如何与新的FancyBowl交互?我只能想到两个选项都“不错”,但都不令人满意。

  1. FancyDog除了通过Dog继承的Bowl指针对象外,还拥有FancyBowl指针。从技术上讲,它们可能属于不同的类,但是从概念上讲,FancyDog现在拥有指向同一对象的两个不同的指针,这并不使我觉得自己像一个优雅的编码器。如果我们要学究的话,那也是在浪费记忆,在大多数情况下,这可以忽略不计。

  2. FancyDog动态在每次需要访问派生接口时将其Bowl指针强制转换为FancyBowl指针。如果只需要执行一次或两次,也许对性能的影响并不大,但是这并没有让我感到温暖和模糊。

这仅仅是经典的性能记忆折衷方案吗?还是有更优雅的解决方案?

P.S。请注意,如果尝试使FancyBowl跟踪狗,就会遇到同样的问题。

1 个答案:

答案 0 :(得分:4)

这是“狗/碗”作者设计不佳的问题。考虑以下改进:

class Bowl;

class Dog
{
    virtual Bowl* getBowl() = 0;
};

class Bowl
{
    Dog* m_owner;
};

现在,FancyDog的实现可以容纳一个FancyBowl并返回一个没有问题的指针。

从本质上讲,问题出在其中之一-因为Dog类保留对m_bowl指针进行赋值的权限,因此无法保证它始终指向FancyBowl ,因为Dog可能会重新分配它。在第一种情况下,您保证FancyDog始终有一个FancyBowl,但是您无法保证Dog和FancyDog可以看到同一碗。在第二种情况下,您不知道该碗将是FancyBowl,但您知道您至少总是在使用同一碗。

如果Dog类声明了一个更简单的接口,仅需要该类实际需要的接口(即,您有一个Bowl可供读取),那么问题就消失了。如果您不喜欢简单的运行时多态getter,则上述方法还有更复杂的静态变体。