C# 接口(interface)与抽象类(abstract)的区别

发布时间 2023-09-27 14:47:06作者: soliang

【虚方法】

virtual关键字用于在基类中修饰方法(或属性、索引器或事件声明),并且允许在派生类中重写这些对象(即override可写可不写)。

virtual的使用会有两种情况:
情况1:在基类中virtual方法在子类中没用override重写。那么在对子类实例的调用中,该虚方法使用的是基类定义的方法。
情况2:在基类中virtual方法在派生类中使用override重写。那么在对子类实例的调用中,该虚方法使用的是子类重写的方法。

 

【抽象方法】

abstract关键字只能用在抽象类中修饰方法,并且没有具体的实现(没有方法体),抽象方法必须放在抽象类中(但抽象类中可以没有抽象方法)。
非抽象类的派生类必须全部实现父类的抽象方法和抽象访问器,使用override关键字来实现。

 

【接口】

接口用于描述一组类的公共方法/公共属性
接口中的方法没有具体实现,也就是没有方法体,必须由继承者去实现而且必须全部实现。
接口中的方法不需要修饰符,默认就是公有的(Default / Public)
接口可以包含方法、属性、索引器、事件。不能包含任何其他的成员,例如:常量、字段、域、构造函数、析构函数、静态成员

 

【虚方法 VS 抽象方法】

虚方法和抽象方法都可以供派生类重写
1. 虚方法必须有实现部分,抽象方法没有提供实现部分,抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化;而虚方法提供了选择,可以覆盖可以不覆盖。
2. 抽象方法只能在抽象类中声明,虚方法不是。

 

【抽象 VS 接口】

抽象类和接口都不能实例化(无法New创建实例,只能被继承)
抽象类可以包含非抽象方法,而接口只能包含抽象方法
一个类可以实现多接口,单继承。(可以继承多个接口,但只能继承单个类)

在学习c#接口(interface)和抽象类(abstract)的时候 发现接口和抽象类极为相似,比如说:继承后都需要重写,或者都不能通过new关键字来实例化… ,那么他们之间到底有什么区别与联系 ?

一、接口的特征
​ 1、接口使用interface关键字声明

​ 2、接口中的成员有属性、方法、事件,索引器并且都没有实现部分,可以说是没有方法体

​ 3、接口中不能声明字段和常量,接口中的成员不能使用任何修饰符

​ 4、继承接口的类或结构必须隐式或显式实现接口中的所有成员

​ 5、一个接口允许继承多个接口,一个类也可以继承多个接口,但是只能继承一个基类。

C#不允许多重类继承(子类继承多个父类),但允许多重接口实现(子类继承多个父接口)。

​ 6、接口不能通过new关键字来实例化

​ 7、类或结构继承接口或不用使用override关键字即可实现

​ 8、接口中没有实例构造函数

 1 public interface IPict
 2 {
 3   void DisplayImage();
 4  }
 5 
 6  public interface IPictManip
 7 {
 8   void DisplayImage();
 9 }
10 
11 public class MyImages: IPict, IPictManip
12 {
13     void IPict.DisplayImage(){ //如果用显式接口实现方法,则不需使用访问修饰符
14     Console.WriteLine("DisplayImage的IPict实现");
15 }
16 
17 void IPictManip.DisplayImage()
18 {
19     Console.WriteLine("DisplayImage的IPictManip实现");
20 }
21 
22 
23 static void Main(string[] args)
24 {
25     MyImages objM = new MyImages();
26     IPict Pict = objM; //IPict引用
27     Pict.DisplayImage();
28 
29     IPictManip PictManip = objM; //IPictManip引用
30     PictManip.DisplayImage();
31  }

 

二、抽象类的特征
​ 1、抽象类中允许有实例方法,也就是说抽象类中除了抽象方法以外,其他的成员允许有具体的实现

​ 2、抽象类中的抽象方法没有实现部分,也就是说没有方法体,并且继承此抽象类的非抽象类必须使用override关键字来重写抽象类中的所有方法

​ 3、在抽象类中可以声明任何类成员,并且类成员可以使用任意的修饰符 (接口不行)

​ 4、抽象类仅能让非抽象类和抽象类继承

​ 5、非抽象类继承抽象类后必须重写(实现)抽象类中的所有抽象方法,抽象类继承抽象类后可以只实现部分抽象方法

 

三、总结
1、接口与抽象类的相同点
​ (1)都不能使用new关键字来实例化

​ (2)成员方法都没有实现部分,或者说都没有方法体

​ (3)继承他们的,都必须实现他们的成员方法 

2、接口和抽象类的不同点
接口(interface) 抽象类(abstract)
接口中不能声明字段和常量,接口成员有:属性、方法、事件、索引器 抽象类中可以声明任何类成员
在接口中只能定义成员,但不能具体实现。(没有方法体) 在抽象类中除了抽象方法以外,其他成员允许有具体的实现
接口中没有实例构造函数,也就是说没有构造函数 抽象类中有构造函数
接口成员不能使用任何访问修饰符 抽象类中的类成员可以使用任意的访问修饰符
继承接口的类或结构必须隐式或显式实现接口中的所有成员,否则需要将实现类定义为抽象类,并将接口中未实现的成员以抽象的方式实现 继承抽象类的类必须重写实现抽象类中的所有抽象方法,或者抽象类继承抽象类,可以重写部分抽象方法
接口不能作为派生类继承 抽象类可以继承非抽象类或抽象类
接口可以作为基类来多继承:接口、类和结构 抽象类可以作为基类只能实现单继承,只能让非抽象类或者抽象类继承

 

抽象类(abstract)和接口(interface)的实现


抽象类
  抽象方法是没有代码实现的方法,使用abstract关键字修饰;

抽象类是包含0到多个抽象方法的类,其不能实例化。含有抽象方法的类必须是抽象类,抽象类中也可以包含非抽象方法;
重写抽象类的方法用override关键字。

 1 //定义一个抽象类,包含一个抽象方法,但该方法未实现
 2 abstract class MyAbs
 3 {
 4     public abstract void AbMethod();
 5 }
 6  
 7 //定义一个非抽象派生类,只能继承一个类
 8  class MyClass:MyAbs
 9 {
10     public override void AbMethod(){
11     Console.WriteLine("此MyClass中实现父类中未实现的抽象方法!");
12  }
13 
14 //在主程序中实例化一个MyClass对象,并调用AbMethod方法
15 static void Main(string[] args)
16 {
17     MyClass objMyClass = new MyClass();
18     objMyClass.AbMethod();
19 }

 

虚方法(virtual)与抽象方法(abstract)的区别

虚方法必须要有方法体(方法体可以没有内容,但必须保留大括号),抽象方法不允许有方法体(不能有大括号);
父类的虚方法:

protected virtual void Initialization()
{

}

子类的方法重写:

protected override void Initialization()
{
    MsgTypeName = NAME;
    LoadChildrenUIFormList = new List<string>
    {
         "TrainingGround_SkillInfoBoxUI"
    };
    CurrentUIType.UIForms_ShowMode = UIFormShowMode.HideOther;
}    

 

2. 虚方法可以被子类重载(override)(也可以不重载,在对子类实例的调用中,该虚方法使用的是基类定义的方法),抽象方法必须被子类重载(必须重新继承实现);

3.虚方法除了在 (sealed) 密封类中都可以写,抽象方法只能在抽象类中写(抽象类中不是必须要有抽象方法,抽象方法可以为0个)。

 

接口
  接口是一套规范,遵守这个规范就可以实现功能。

接口中只定义方法的原型,不能有字段和常量;
继承接口的类 必须实现接口中所有的方法 才能实例化

 


1 //隐式声明为public
2 public interface IPict{
3 //只有方法声明,没有访问修饰符,没有实现
4 int DeleteImage();
5 void DisplayImage();
6 }


  定义派生自接口的类,并实现所有接口中的方法

 

1 public class MyImages: IPict{
2 //第一个方法的实现
3 public int DeleteImage(){
4 Console.WriteLine("DeleteImage实现!");
5 }
6
7 //第二个方法的实现
8 public void DisplayImage(){
9 Console.WriteLine("DisplayImage实现!");
10 }
11 }


  在主程序中实例化一个MyImages对象,并调用DeleteImage和DisplayImage方法

 

1 static void Main(string[] args){
2 MyImages ofjM = new MyImages();
3 objM.DisplayImage();
4 int t = objM.DeleteImage();
5 Console.WriteLine(t);
6 }


多重接口实现
  C#不允许多重类继承(子类继承多个父类),但允许多重接口实现(子类继承多个父接口)。但如果发生命名冲突就需要使用前缀进行显式接口实现或调用。如果继承接口的类中用显示方法实现接口中的方法时,实现方法不需加访问修饰符(public)

 

1 public interface IPict{
2 void DisplayImage();
3 }
4
5 public interface IPictManip{
6 void DisplayImage();
7 }
8
9 public class MyImages: IPict, IPictManip{
10 void IPict.DisplayImage(){ //如果用显式接口实现方法,则不需使用访问修饰符
11 Console.WriteLine("DisplayImage的IPict实现");
12 }
13 void IPictManip.DisplayImage(){
14 Console.WriteLine("DisplayImage的IPictManip实现");
15 }
16 }
17
18 static void Main(string[] args){
19 MyImages objM = new MyImages();

20 IPict Pict = objM; //IPict引用
21 Pict.DisplayImage();

22 IPictManip PictManip = objM; //IPictManip引用
23 PictManip.DisplayImage();

24 }

 

 

使用自定义接口
  接口作为参数使用:接口作为参数传递了实现接口的对象

 

1 //无论谁收作业参数类型部分都不需做任何改变
2 private void DoCollectHomework(IHomeworkCollector collector){
3 collector.CollectHomework();
4 }
5
6 DoCollectHomework(scofield);


  接口作为返回值使用:接口作为返回值返回了一个实现接口的对象

 

1 private IHomeworkColletor CreateHomeworkCollector(string type){
2 switch(type){
3 case "student":
4 collector = new Student("Scofield", Genders.Male, 28, "越狱");
5 break;
6 }
7 //返回一个实现该接口的对象
8 return collector
9 }
10
11 collector.CollectHomework();

————————————————
版权声明:本文为CSDN博主「Peter_Gao_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42672770/article/details/107730430