如果我可以用抽象类做的所有事情都可以用普通的超类来做,那么当我可以使用普通的超类时,为什么还要使用抽象类呢?
3 回答
我认为评论和答案已经暗示了这一点,但我想更直白地说:你不能用普通的超类做所有你可以用抽象类做的事情。抽象类允许您定义方法的签名而不包括其实现,并且抽象类不允许您直接实例化它。
因此,如果我有 3 个方法的类签名并且我不想共享其中任何一个的实现,我将使用接口。如果我想共享其中一个方法的实现,我将使用一个抽象类,然后将该类中的两个方法设为抽象。如果我想共享方法的所有实现,我将使用抽象类,如果直接实例化它从来没有意义,或者我将使用常规类。
(这是基于我在 C# 方面的经验。不同语言的细节有所不同。)
当您需要以通用方式表示许多相似的事物时,抽象类非常有用。
例如,假设您想在代码中表示一个动物园,并且您需要获取杂货清单以确保您有正确的食物。你如何代表所有动物最喜欢的食物?各自发出什么噪音?他们如何移动呢?您可以尝试使用超类来保存食物、噪音和动作的大列表,但更容易为 Animal 定义一个通用定义,然后让每个动物提供自己的实现细节:
public class Zoo {
public Animals[] AnimalsInZoo { get; set;}
public List<Food> GetGroceryList(){
List<Food> groceries = new List<Food>();
foreach(Animal a in Animals[]){
groceries.Add(a.FavoriteFood);
}
return groceries;
}
public void MakeAnimalsSing(){
foreach(Animal a in Animals[]){
a.MakeNoise();
}
}
}
抽象的 Animal 类看起来像:
public abstract class Animal {
public abstract void MakeNoise();
public abstract Food FavoriteFood { get; }
public abstract void Move();
}
并说动物园有两种动物:
public class Panda : Animal{
public override void MakeNoise(){
// grunt
}
public override void Move(){
// walk
}
public override Food FavoriteFood {
get {
return new Bamboo();
}
}
}
public class Parrot: Animal{
public override void MakeNoise(){
// talk
}
public override void Move(){
// fly
}
public override Food FavoriteFood {
get {
return new Cracker();
}
}
}
通过拥有一个通用的抽象类,我可以轻松地处理任意数量的不同动物类型,而无需明确知道我正在使用哪一种,但每种动物都可以以自己的方式行事。
超类无法提供那种灵活性或细节。
基类提供自己的方法实现。这些实现有时可以被覆盖(取决于语言)。
抽象类不提供默认实现,每个继承类都需要根据具体情况实现方法。
上述细节可能因语言而异。阅读相应的文档。
考虑这个例子:
一个Number
抽象类有一个add()
方法。AOddNumber
和一个EvenNumber
子类需要实现几乎相同的add()
方法,所以那里有一些代码重复。在这里,拥有一个超类更有意义(或者,至少拥有一个 的RealNumber
子类Number
)。
但是,考虑Complex
作为Number
如果数字不是抽象的子类,add()
在(假设它是实数加法算法)中找到的方法Number
对复数没有意义。这里抽象类更有意义。某些语言允许您覆盖超类方法,但在这种情况下这有点尴尬。