如果我可以用抽象类做的一切,我可以使用常规超类, 当我可以使用常规超类时,为什么我会使用抽象类?
答案 0 :(得分:12)
我认为这些评论和答案已经暗示了这一点,但我想更坦率地说明:你不能用普通的超级类来完成所有事情,你可以用抽象类来做。抽象类允许您定义方法的签名而不包括其实现,并且抽象类将不允许您直接实例化它。
因此,如果我有3个方法的类签名,并且我不想共享其中任何一个的实现,我将使用一个接口。 如果我想分享其中一个方法的实现,我将使用一个抽象类,然后在该类抽象中创建两个方法。 如果我想要共享方法的所有实现,我将使用抽象类,如果它直接实例化它是没有意义的,或者如果它的话我将使用常规类。
(这是基于我在C#方面的经验。语言之间的细节不同。)
答案 1 :(得分:1)
基类提供自己的方法实现。有时可以覆盖这些实现(取决于语言)。
抽象类没有提供默认实现,每个继承类都需要根据具体情况实现这些方法。
上述细节因语言而异。阅读相应的文档。
请考虑以下示例:
Number
抽象类具有add()
方法。 OddNumber
和EvenNumber
子类需要实现几乎相同的add()
方法,因此存在一些代码重复。在这里,拥有一个超级类更有意义(或者,至少有一个RealNumber
的{{1}}子类。
但是,如果Number
的数字不是抽象的,则将Complex
视为Number
的子类,add()
中找到Number
方法(假设它是实数加法算法)复杂的数字是没有意义的。这里抽象类更有意义。有些语言允许你覆盖超类方法,但在这种情况下这有点尴尬。
答案 2 :(得分:1)
当您需要以通用方式表示许多类似事物时,抽象类非常有用。
例如,假设你想在代码中代表动物园,你需要获得购物清单以确保你有合适的食物。你如何代表所有动物最喜欢的食物?每个人产生什么噪音?他们如何移动怎么样?您可以尝试使用超类来保存食物,噪音和动作的大列表,但是对于动物有一个共同的定义更容易,然后让每只动物提供自己的实现细节:
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();
}
}
}
通过一个共同的抽象类,我可以轻松地使用任意数量的不同动物类型,而无需明确知道我正在使用哪一个,但每个都可以按照自己的方式行事。
超类只是无法提供这种灵活性或细节。