C#中的虚方法、抽象方法、抽象类、接口的联系与区别

虚方法的关键字是virtual
抽象方法的关键字是abstract
重写都是override 虚方法也可以new
虚方法和抽象方法的区别:
虚方法:可以在抽象类和非抽象类中定义,可以写在父类中,在子类中可以被重写,在定义虚方法时必须实现虚方法
(在定义虚方法时需要写实现方法的代码或者至少要写一个分号)

抽象方法:必须定义在抽象类中,必须写在父类中,在子类中必须被重写,在定义抽象方法时不能实现方法
(在定义抽象方法时不能有大括号和代码)
注:如果我们实现的这个功能它的一部分功能(输出)要写在父类中,而且在不同的子类中需要重写,那么在父类中的方法必须定义为虚方法,
否则,如果在父类中只需要指定有什么功能,但不需要实现,这个时候我们就把父类中的方法定义为抽象方法。

说说抽象类的理解吧:
既然是抽象类,那么就是对事物的抽象描述,它描述的是个体的共性。那马这种动物来说,我们所说的马就是一个抽象类。世界上存在很多种马,白马,黑马,红马......如果没有抽象的概念,我们就没法获得世界上所有马,因为我们要说马的时候,必须指定是哪种马!但是我们其实是有抽象的概念的,我们定义了马这样的一个概念,用来指代世界上所有的马。但马在这个世界上并不是真实存在的,你所能看见的马一定是某一种类型的马!

所以说,抽象类就是这样一种类,描述了一种事物的共性,它不能实例化,只能通过它的子类实例化。
抽象方法:抽象方法一定是抽象类里面的,抽象的方法没有主体,就是没有实现代码,它的实现是由子类实现的。如果一个抽象类里面全是抽象方法的画,那么这个类和接口的功能基本就是一致,而抽象类和接口不一样的地方就在于抽象类可以有非抽象的方法。

virtual 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。例如,此方法可被任何继承它的类重写。

标记为虚方法的方法,可以在子类被重写。也就说子类可以变异。还是马类为例:
public abstract class 马类
{
//长毛这个方法是抽象的方法,因为它的实现
//必须是具体的那种马去实现的
public abstract void 长毛();
//消化这个方法是虚方法,所有的马
//都按这个方法去消化东西,也可以变异
public virtual void 消化()
{
Console.WriteLine("1小时消化1千克食物");
}
}
public class 红马 : 马类
{
public override void 长毛()
{
Console.WriteLine("我长的是红毛");
}
//在这里变异了,消化能力超强
public override void 消化()
{
Console.WriteLine("1小时消化1吨食物");
}
}

在这里要说明一点是隐藏与重写的区别。

重写:继承时发生,在子类中重新定义父类中的方法,子类中的方法和父类的方法是一样的

隐藏:在派生类中使用new声明一个跟父类一样的方法,那么父类的方法将被隐藏起来,但是还是存在的,可以用base来调用。这样相当于子类有两套名称一样的方法。

public virtual void prinf() 

Console.WriteLine ("这是虚方法"); 


public override void prinf() 



Console.WriteLine ("这是新的方法"); 


public new void prinf() 

Console.WriteLine ("这是另一个新的方法"); 
 
 
 
 

下面的例子说明了C#虚拟方法与非虚方法的区别。

例子:

 
 
  1. using System;
  2. class A
  3. {
  4. public void F(){Console.WriteLine("A.F");}
  5. public virtual void G(){Console.WriteLine("A.G");}
  6. }
  7. class B:A
  8. {
  9. new public void F(){Console.WriteLine("B.F");}
  10. public override void G(){Console.WriteLine("B.G");}
  11. }
  12. class Test
  13. {
  14. static void Main()
  15. {
  16. B b=new B();
  17. A a=b;
  18. a.F();
  19. b.F();
  20. a.G();
  21. b.G();
  22. }
  23. }

例子中,A类提供了两个方法:非虚的F和C#虚拟方法 G.类B则提供了一个新的非虚的方法F,从而覆盖了继承的F;类B同时还重载了继承的方法G.那么输出应该是:

A.F

B.F

B.G

B.G

注意到本例中,方法a.G()实际调用了B.G,而不是A.G.这是因为编译时值为A,但运行时值为B,所以B完成了对方法的实际调用。


 
 
 

猜你喜欢

转载自blog.csdn.net/HYB2012/article/details/54668911