C#程序设计自学经典
上QQ阅读APP看书,第一时间看更新

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)抽象类中的成员可以是私有的(只要不是抽象的)、受保护的、内部的或受保护的内部成员,但接口中的成员必须是公共的。

所以,抽象类和接口这两种类型用于完全不同的目的。抽象类主要用作对象系列的基类,共享某些主要特性,例如共同的目的和结构。接口则主要用于类,这些类在基础水平上有所不同,但仍然可以完成某些相同的任务。