C# 抽象方法(abstract )与虚方法(virtual)的区别
虚方法和抽象方法都可以供派生类重写,主要有以下区别:
1.抽象方法没有提供实现部分,是一种强制派生类重写的方法,否则派生类将不能被实例化。
虚方法必须有实现部分,并为派生类提供了重写该方法的选项。
1 //抽象方法 2 public abstract class Animal 3 { 4 public abstract void Sleep(); 5 public abstract void Eat(); 6 }
1 //虚方法 2 public class Animal 3 { 4 public virtual void Sleep(){} 5 public virtual void Eat(){} 6 }
2.抽象方法只能在抽象类中声明,抽象方法必须在派生类中重写。(如果一个类包含抽象方法,那么该类也是抽象的,也必须是抽象的。)
虚方法不是也不必要重写。
//这样写编译器会报错。 public class Animal { public abstract void Sleep(); public abstract void Eat(); }
3.抽象方法必须在派生类中重写,这一点跟接口类似,抽象方法不能声明方法体,包含抽象方法的类不能被实例化。
虚方法不是必须在派生类中重写,虚方法可以有方法体,包含虚方法的类可以被实例化。
1 //编译器会报错,因为我们没有实现抽象类中所有抽象方法。 2 public abstract class Animal 3 { 4 public abstract void Sleep(); 5 public abstract void Eat(); 6 } 7 8 public class Cat : Animal 9 { 10 public override void Sleep() 11 { 12 Console.WriteLine( "Cat is sleeping " ); 13 } 14 // we need implement Animal.Eat() here 15 }
什么时候使用virtual什么时候使用abstract?
a) virtual重点是实现多态,同一个方法能做不同的事情,也就是当一个方法会有不同的操作的时候要用virtual,例如:支付方法 pay(),可能通过微信去支付、也可能通过支付宝或者其他方式去支付,这个时候定义pay()方法的时候最好是用virtual修饰。
b) 作为一个必须存在的方法的时候用abstract,比如要定义一个人类对象Class Person{}和一个鸟类对象Class Bird{},人是动物,鸟也是动物,所以一般会先定义一个共同的基类Class animal{},然后让人类和鸟类对象都继承这个基类。这个基类可以有共通的属性和方法,比如行走方法walk(),发声方法voice(),在基类中这两个方法都是不需要实现的,只需要在Person和Bird类中实现就可以了【Person和Bird类必需要实现这两个方法,这也保证了所有继承animal类的类都需要有walk()和voice()方法】,所以定义walk()和voice()方法的时候可以用abstract修饰
虚拟方法和抽象方法有什么区别与联系:
1.抽象方法只有声明没有实现代码,需要在之类中实现;虚方法有声明和实现代码,并且可以在子类中重写,也可以不重写使用父类的默认实现。
2.抽象类不能被实例化(不可以new),只能实例化实现了全部抽象方法的派生类;而包含虚方法的类可以实例化。
3.虚方法与多态性关系密切,虚方法允许派生类完全或部分重写该类的方法,需些方法体。抽象方法只是一个定义,没有方法体,也就是没有{},也不要在里面写内容。
4.抽象方法和虚拟方法两个相相的一点是都用override重写。
非抽象类与接口的差别:
非抽象类和接口的差别很大,它们的差别主要表现在以下几个方面:
1、非抽象类可以有成员变量、常量和构造函数,而接口中不能存在常量、域、操作符、构造函数或析构函数,而且不能包含任何静态成员。
2、一个非抽象类可以继承多个接口,而只能继承一个类;
3、非抽象类中可以定义具体的方法和实现,而接口只定义方法没有具体的实现;
4、接口成员一定是公共的,而且不能声明为虚拟或者是静态的,而非抽象类中是没有这些限制。
5、非抽象类可以被实例化,而接口不可以。一般来说,非抽象类的内容较接口要丰富得多,非抽象类可以有面向对象所有的绝大部分组成元素。但是接口相对于非抽象类来说更加灵活,两者在使用上冲突不大,在使用的时候视具体情况而定。
抽象类和接口的使用:
1、如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单的方法来控制组件版本。
2、如果创建的功能将在大范围的全异对象间使用,则使用接口。如果要设计小而简练的功能块,则使用接口。
3、如果要设计大的功能单元,则使用抽象类.如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。
4、抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。