5.5 抽象类与抽象方法的应用
如果一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为其派生类的一个基类,这样的类就是抽象类,在抽象类中声明方法时,如果加上abstract关键字则为抽象方法。
5.5.1 抽象类的声明
抽象类主要用来提供多个派生类可共享的基类的公共定义,抽象类与非抽象类的主要区别如下。
(1)抽象类不能直接被实例化。
(2)抽象类中可以包含抽象成员,但非抽象类中不可以。
(3)抽象类不能被密封。
C#中,使用abstract关键字来声明抽象类,语法格式如下:
访问修饰符 abstract class 类名 { //类成员 }
以下代码片段演示了声明一个名为MyAbstractClass的抽象类,其中包含一个string类型的变量msg,以及一个无返回值方法ShowMsg。
public abstract class MyAbstractClass { public string msg="Hello"; public void ShowMsg() { Console.WriteLine(msg); } }
5.5.2 抽象方法的声明
抽象方法是在声明方法前加上abstract关键字,抽象方法的特点如下。
(1)抽象方法是隐式的虚方法,抽象方法只能在抽象类中声明。
(2)抽象方法不能使用private、static和virtual修饰符。(抽象方法默认是一个virtual方法。)
(3)抽象方法声明不提供具体的实现,没有方法体。若要实现抽象方法,需要在派生类(非抽象类)中进行重写该抽象方法,继承类只有实现所有抽象类的抽象方法后才能被实例化。
以下代码片段演示了声明一个名为MyAbstractClass的抽象类,并在其中声明一个无返回值的抽象方法ShowMsg。
public abstract class MyAbstractClass { public abstract void ShowMsg(); }
5.5.3 如何使用抽象类与抽象方法
本节通过一个简单的示例来讲解下抽象类与抽象方法的使用。
例5-10:抽象类与抽象方法的使用(ConsoleAbstract)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleAbstract { class Program { static void Main(string[] args) { Animal animalDog = new Dog(); Animal animalCat = new Cat(); Dog dog = new Dog(); Cat cat = new Cat(); animalDog.Barking(); animalCat.Barking(); dog.Barking(); cat.Barking(); Console.ReadLine(); } } public abstract class Animal { public abstract void Barking(); } public class Dog : Animal { public override void Barking() { Console.WriteLine("汪~汪~汪~"); } } public class Cat : Animal { public override void Barking() { Console.WriteLine("喵~喵~喵~"); } } }
运行结果如图5-10所示。
图5-10 抽象类与抽象方法的使用
在此例中,声明了一个名为Animal的抽象类,Animal类中定义一个名为Barking的抽象方法。子类Dog、Cat分别继承自抽象类Animal,并分别重写父类中的抽象方法Barking。Main方法中,分别使用子类的对象来实例化父类以及子类本身,并调用其Barking方法输出信息。
抽象类的特点如下。
(1)抽象类使用abstract修饰符,并且它只能用作基类。
(2)抽象类不能实例化,当使用new运算符对其实例时会出现编译错误。
(3)允许(但不要求)抽象类包含抽象成员,非抽象类不能包含抽象成员。
(4)抽象类不能被密封。
(5)抽象类可以被抽象类所继承,结果仍是抽象类。
那么,抽象类和接口有什么异同呢?
(1)它们的派生类只能继承一个基类,即只能继承一个抽象类,但是可以继承多个接口。
(2)抽象类中可以定义成员的实现,但接口中不可以。
(3)抽象类中包含字段、构造函数、析构函数、静态成员或常量等,接口中不可以。
(4)抽象类中的成员可以是私有的(只要不是抽象的)、受保护的、内部的或受保护的内部成员,但接口中的成员必须是公共的。
所以,抽象类和接口这两种类型用于完全不同的目的。抽象类主要用作对象系列的基类,共享某些主要特性,例如共同的目的和结构。接口则主要用于类,这些类在基础水平上有所不同,但仍然可以完成某些相同的任务。