【问题标题】:Implementing partial C++ Interface in parent class在父类中实现部分 C++ 接口
【发布时间】:2017-06-22 22:58:10
【问题描述】:

我有一个独特的案例,我需要两层接口,并希望有两层类来实现它们:

class IFood {
public:
    virtual ~IFood() = default;
    virtual int GetColor() const = 0;
};

class IFruit : public IFood {
public:
    virtual int GetAverageSeedCount() const = 0;
};

class GreenFood : public IFood {
    virtual int GetColor() const override {return GREEN;}
};

class GreenApple : public GreenFood, public IFruit {
    virtual int GetAverageSeedCount() const override {return 5;}
};

(我意识到这些接口并不完全合理。抱歉。)

在某些情况下,我可能有一个 IFood 对象的集合,但在其他情况下,我将有一个 IFruit 对象的集合。实际上,IFood 所代表的接口有 5-8 个函数。

如果这段代码可以编译并运行,我会被设置。不幸的是,它失败了,因为编译器没有意识到GreenApple 实现了IFood API(缺少GetColor)。这确实存在于我们扩展的基础GreenFood 中,但拆分接口实现似乎并不能让编译器满意。

对于 IFood 中的每个函数,我可以让 IFruit 实现它并直接调用 ParentClass::functionName()。但是在 IFood 中有 5-8 个函数和数十种潜在的水果类型,这并不像我想要的那样优雅。

我很好奇是否有任何解决方案可以让编译器在父类中找到这些缺失的 API,或者有什么好方法可以让我重组我的接口以保持优雅?

如果需要,我可以提供更具体的示例。感谢您的任何提示!

【问题讨论】:

    标签: c++ oop c++11 multiple-inheritance


    【解决方案1】:

    对 IFruit 和 GreenFood 中的基类使用 Virtual 关键字。

    class IFood {
    public:
        virtual ~IFood() = default;
        virtual int GetColor() const = 0;
    };
    
    class IFruit : public virtual IFood {
    public:
        virtual int GetAverageSeedCount() const = 0;
    };
    
    class GreenFood : public virtual  IFood {
        virtual int GetColor() const override {return GREEN;}
    };
    
    class GreenApple : public GreenFood, public IFruit {
        virtual int GetAverageSeedCount() const override {return 5;}
    };
    

    【讨论】:

    • 非常感谢!这完美地解决了它。我真的没有想过这是钻石图案。我将不得不对虚拟继承的任何潜在缺点进行自我更新......
    • 是的。它发生了。在解决复杂问题时,我们往往会忘记基础知识。
    【解决方案2】:

    有几种方法可以解决这个问题。

    首先GreenApple知道它继承自GreenFoodIFruit,而IFruit继承了自己对GetColor()实现的要求,在GreenFood()中实现,所以从一个角度来看,这是GreenApple 的责任:

    class GreenApple : public GreenFood, public IFruit {
        virtual int GetAverageSeedCount() const override {return 5;}
        virtual int getColor() const override {
             return GreenFood::GetColor();
        }
    };
    

    一个稍微干净的变体,避免丑陋的显式类引用:

    class GreenFood : public IFood {
        virtual int GetColor() const override
        {
             return GreenFoodColor();
        }
    
        int GreenFoodColor() const
        {
               return GREEN;
        }
    };
    
    class GreenApple : public GreenFood, public IFruit {
        virtual int GetAverageSeedCount() const override {return 5;}
        virtual int getColor() const override {
             return GreenFoodColor();
        }
    };
    

    这会起作用,但这仍然会导致GreenApple 两次从IFood 继承。这可能会产生自己的问题。

    避免重复继承的另一种解决方案是不让IFruit 直接继承自IFood,而是要求其子类以某种方式从该接口继承:

    class IFruit {
    public:
        virtual int GetAverageSeedCount() const = 0;
    
        virtual IFood &getIFood()=0;
    
        virtual const IFood &getIFood() const=0;
    };
    
    class GreenApple : public GreenFood, public IFruit {
        virtual int GetAverageSeedCount() const override {return 5;}
    
        virtual IFood &getIFood() override { return *this; }
    
        virtual const IFood &getIFood() const { return *this; }
    };
    

    任何看到IFruit 的人都知道IFood 隐藏在这附近的某个地方,某个地方。或许可以在其中插入一个operator IFood &,以使整个过程更加透明。

    【讨论】:

      猜你喜欢
      • 2015-01-05
      • 2018-05-12
      • 2012-02-28
      • 2011-02-06
      • 1970-01-01
      • 2014-09-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多