我有一个独特的案例,我需要两层接口,并希望有两层类来实现它们:
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,或者我有什么好的方法来重构我的接口以保持优雅?
如果需要,我可以提供更具体的例子。感谢您的任何提示!
答案 0 :(得分:2)
在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;}
};
答案 1 :(得分:-1)
有几种方法可以解决这个问题。
首先,GreenApple
知道它继承自GreenFood
和IFruit
,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 &
,使整个过程更加透明。