class Shape { virtual double area()=0; }; class Square : public Shape { virtual void setLength(double length)=0; }; class Rectangle : public Square { virtual void setWidth(double width)=0; };
我尝试通过以下方式实现Square和Rectangle:
class SquareImpl : public Square { /*implementation*/ }; class RectangleImpl : public SquareImpl, Rectangle { /*implementation*/ };
其中RectangleImpl继承SquareImpl和Rectangle以重用,比如SquareImpl :: area().然而,当我尝试编译,有两个问题引起:首先,在SquareImpl所有方法没有得到正确继承和我必须手动重新实现RectangleImpl ::区域()和RectangleImpl :: setLength().其次,这仍然引入了Shape是RectangleImpl模糊基础的钻石问题.
如果我从Shape继承了Square,我可以编译代码,但我认为性能不会随着添加的派生接口的增加而扩展.同样奇怪的是,尽管SquareImpl :: area()被很好地继承,但RectangleImpl仍然不继承SquareImpl :: setLength(). (忽略这里的实用性)
另一种解决方案可能是使接口彼此独立,即使Square不从Shape继承.但是,如果我定义采用Square *指针的函数,那么这样做会使我无法访问Shape中的方法.它还会使Shape和Square之间的static_cast无法实现.
所以我的问题是,在C中是否有任何其他设计模式来解决接口类和实现类之间的这种并行继承,而不需要虚拟继承?
(编辑说明:上面的示例代码只是我对接口和实现之间并行继承的虚拟说明.我知道有更好的方法来实现形状,但我的问题不在于如何实现形状.)
你在这里有的是 Diamond Problem的情况,它可以在允许多重继承的任何OO语言中发生.顺便说一下,这就是为什么Java的设计者决定不进行多重继承,并想出了接口的概念.C处理钻石问题的方式是Virtual Inheritance.
并且,正如codymanix指出的那样,正方形和矩形是面向对象设计的一个非常糟糕的例子,因为就OO而言,a square is not a rectangle.
多点积分.首先,你在这里做的术语是多重继承,而不是“并行继承”.其次,在这种特殊情况下,拥有一个Square类和一个SquareImpl类是没有意义的.如果您认为您可能有不同的Square实现,那么您应该只有一个基类,它提供默认实现和虚拟函数,如果需要,可以由派生类覆盖.换句话说,您应该将Square和SquareImpl转换为具有虚函数的一个类.
你当然可以使用像Java接口这样的抽象C类,但大多数时候没有理由这样做.接口被添加到Java中,正是为了避免缺少多重继承.在C中你可以继续使用多重继承,尽管你应该总是明智地做到这一点.