我正在寻找使用继承的糟糕示例。我不是很有创意,所以这是我能想到的最好的:
class Car : public Engine {}
汽车有引擎,但它不是引擎。
这可能有助于解释这个概念,但我相信还有更多的说明性例子?
答案 0 :(得分:5)
“经典”示例; - ):
public class Stack extends Vector {
...
}
堆栈不是矢量。
如果Stack扩展了Vector,你可以在每个给定的索引处插入/删除,而你应该只允许通过推/弹来添加/删除元素。
答案 1 :(得分:4)
几乎使用任何使用继承的示例,而不考虑基类的行为。
一个典型的例子是Square
和Rectangle
之间的关系。当然,在数学中,正方形是一种矩形。但是,在软件设计中,正方形的行为不像矩形:
public class Rectangle
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }
}
public class Square : Rectangle
{
public override int Width
{
get { return base.Width; }
set
{
base.Width = value;
base.Height = value;
}
}
public override int Height
{
get { return base.Height; }
set
{
base.Height= value;
base.Width = value;
}
}
}
如果另一个类Client
需要Rectangle
但得到Square
,则Client
会中断,因为它希望其Rectangle
拥有Width
1}}和Height
互不影响。
答案 2 :(得分:1)
继承非常有用,但也打破了封装。这意味着您的子类依赖于超类的实现细节;如果超类发生更改,您的子类可能会中断。这是Java中的一个例子,来自Josh Bloch的Effective Java:
public class InstrumentedHashSet<E> extends HashSet<E> {
// number of attempted element insertions
private int addCount = 0;
public int getAddCount() {
return addCount;
}
@Override public boolean addAll<Collection<? extends E> c) {
addCount += c.size();
return super.addAll(c);
}
}
问题是HashSet的addAll()方法在内部使用了它的add()方法,但没有记录它。所以如果你试试
InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
你得到的数字是6而不是3.在这个特殊情况下,这不是很有害,但如果你要添加一个大型集合或进行其他操作,它可能是。
因此,具体类通常不是继承的好主意,除非它们被设计为具有子类。
答案 3 :(得分:0)
这已经讨论多年了,你会发现很多材料/谈话在谷歌上引用这个问题。
public class Square extends Rectangle {
...
}
也许不是很令人惊讶,广场不应该从矩形继承。