虚方法、抽象类与抽象方法

抽象类

何时必须声明一个类为抽象类?(面试题)

当这个类中包含抽象方法时,或是该类并没有完全实现父类的抽象方法时。

abstract 修饰符可用于类、方法、属性、索引和事件。 在类声明中使用 abstract 修饰符以指示某个类仅旨在作为其他类的基类。 标记为 abstract 的成员,或包含在抽象类中的成员,都必须由派生自抽象类的类来实现。

抽象类的特征:

  • 抽象类由abstract关键字修饰,只能用作基类
  • 抽象类可能包含抽象方法和访问器,同时也可以包含非抽象方法和非抽象访问器(只要有一个抽象方法,该类就必须定义为抽象类)
 1     abstract class AbstractClass
 2     {
 3         public abstract int Age { get; }//抽象访问器
 4         public string Name { get { return "张三"; } }//非抽象访问器
 5 
 6         public abstract void AbstractMethod();//抽象方法
 7 
 8         public void Method()//非抽象方法
 9         {
10             Console.WriteLine("抽象类中的非抽象方法");
11         }
12     }
  • 派生自抽象类的非抽象类,必须实现抽象类的所有抽象方法和访问器,否则该子类也必须声明为抽象类
 1     class MyClass : AbstractClass
 2     {
 3         //实现抽象类中的抽象访问器
 4         public override int Age
 5         {
 6             get
 7             {
 8                 return 30;
 9             }
10         }
11         //实现抽象类中的抽象方法
12         public override void AbstractMethod()
13         {
14             Console.WriteLine("在派生类中实现的抽象方法");
15         }
16     }
  • 抽象类不能被实例化(但是抽象类中可以有构造函数),只能通过派生类进行实例化
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //AbstractClass abstractClass = new AbstractClass();//抽象类不能实例化,这种写法会报错
 6             MyClass myclass = new MyClass();
 7             Console.WriteLine(myclass.Age);//30
 8             Console.WriteLine(myclass.Name);//张三
 9             myclass.Method();//抽象类中的非抽象方法
10             myclass.AbstractMethod();//在派生类中实现的抽象方法
11 
12             Console.ReadKey();
13         }
14     }
  • 抽象类不能使用sealed修饰符来修饰,因为abstract和sealed两个修饰符有相反的含义(sealed表示该类不能被继承,abstract表示该类可以被继承)
  • 抽象类可以被抽象类继承,此时抽象的派僧类可以对抽象基类中的抽象方法进行重写,也可以不进行重写,但是必须在该抽象派生类的子类中对其进行重写

抽象方法和抽象访问器

  • 抽象方法使用abstract修饰,使用static和virtual修饰是错误的
  • 抽象方法是隐式的虚方法
  • 只有抽象类才允许声明抽象方法
  • 抽象方法只有方法签名,没有方法具体实现的方法体
  • 在静态属性上是用abstract修饰符是错误的
  • 通过override修饰符,可以在派生类中重写抽象类中的抽象方法和抽象访问器
  • 抽象成员不能是私有的

虚方法

  • 虚方法使用virtual关键字修饰
  • 虚方法不能是私有的
  • virtual修饰符不能与static、abstract、private、override修饰符一起使用
  • 通过override关键字对虚方法进行重写
 1     class Class1
 2     {
 3         public virtual void ShowInfo()
 4         {
 5             Console.WriteLine("虚方法在父类中的实现");
 6         }
 7     }
 8 
 9     class Class2 : Class1
10     {
11         public override void ShowInfo()
12         {
13             Console.WriteLine("虚方法在子类中的实现");
14         }
15     }
16 
17     class Program
18     {
19         static void Main(string[] args)
20         {
21             Class2 c = new Class2();
22             c.ShowInfo();//虚方法在子类中的实现
23 
24             Console.ReadKey();
25         }
26     }

1、当调用一个对象的函数时,系统会先去检查这个对象所属的类,看所调用的函数是否为虚函数;

2、如果不是虚函数,那么它就直接执行该函数。而如果有virtual关键字,也就是一个虚函数,那么这个时候它就不会立刻执行该函数了,而是转去检查对象的实例类。

3、在这个实例类里,他会检查这个实例类的中是否重写该虚函数(通过override关键字),如果是有,那么就马上执行该实例类中的这个重新实现的函数;如果没有的话,系统就会不停地往上找实例类的基类,直到找到第一个重写了该虚函数的基类为止,然后执行该基类中的函数。

抽象方法与虚方法的区别:

  • 抽象方法必须定义在一个抽象类中,虚方法没有特殊要求
  • 抽象方法在基类中不可以有具体的实现,而虚方法在基类中必须有具体的实现
  • 抽象方法要求必须在派生类中对其进行重写;而虚方法可以在派生类中对其进行重写,也可以不对其进行重写

抽象类与接口的相同点:

  • 都可以被继承
  • 都不可以实例化
  • 都可以包含方法声明
  • 派生类都必须实现其未实现的方法

抽象类与接口的区别:

  • 抽象类可以定义字段、属性,可以包含方法的实现,可定义的内容与非抽象类基本一致;而接口只能定义属性、索引器、事件和方法声明,不能包含字段和方法实现
  • 抽象类是一个不完整的类,需要进一步细化扩展;而接口是一个行为规范
  • 抽象类更多的是定义在一系列紧密相关的类之间;而接口大多数是关系疏松但都实现某一功能的类中
  • 抽象类是从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性;接口是为了满足外部调用而定义的一个功能约定, 因此反映的是事物的外部特性
  • 接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法
  • 可以用于支持回调,而继承并不具备这个特征
  • 抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的
  • 如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法
posted @ 2017-07-22 12:14  CS讷于言而敏于行  阅读(1639)  评论(0编辑  收藏  举报