C#虚方法(virtual)和抽象方法(abstract)的区别 - chunlieater/chunlifeet GitHub Wiki

第一种解释:

虚方法和抽象方法都可以供派生类重写,它们之间有什么区别呢?

  1. 虚方法必须有实现部分,抽象方法没有提供实现部分,抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化。如:

view plaincopy to clipboardprint? //抽象方法
public abstract class Animal
{
public abstract void Sleep();
public abstract void Eat();
}

//虚方法
public class Animal
{
public virtual void Sleep(){}
public virtual void Eat(){}
}
[c-sharp] view plain copy //抽象方法
public abstract class Animal
{
public abstract void Sleep();
public abstract void Eat();
}

//虚方法
public class Animal
{
public virtual void Sleep(){}
public virtual void Eat(){}
}

  1. 抽象方法只能在抽象类中声明,虚方法不是。其实如果类包含抽象方法,那么该类也是抽象的,也必须声明为抽象的。如:

view plaincopy to clipboardprint? public class Animal
{
public abstract void Sleep();
public abstract void Eat();
}
[c-sharp] view plain copy public class Animal
{
public abstract void Sleep();
public abstract void Eat();
}

编译器会报错: Main.cs(10): 'VSTest.Animal.Sleep()' is abstract but it is contained in nonabstract class 'VSTest.Animal' Main.cs(11): 'VSTest.Animal.Eat()' is abstract but it is contained in nonabstract class 'VSTest.Animal'

  1. 抽象方法必须在派生类中重写,这一点跟接口类似,虚方法不必。如:

view plaincopy to clipboardprint? public abstract class Animal
{
public abstract void Sleep();
public abstract void Eat();
}

public class Cat : Animal
{
public override void Sleep()
{
Console.WriteLine( "Cat is sleeping" );
}
// we need implement Animal.Eat() here

}
[c-sharp] view plain copy public abstract class Animal
{
public abstract void Sleep();
public abstract void Eat();
}

public class Cat : Animal
{
public override void Sleep()
{
Console.WriteLine( "Cat is sleeping" );
}
// we need implement Animal.Eat() here

}

编译器会报错:Main.cs(14): 'VSTest.Cat' does not implement inherited abstract member 'VSTest.Animal.Eat()',因为我们没有实现抽象类中所有抽象方法。

此种解释转自:http://www.cnblogs.com/michaelxu/archive/2008/04/01/1132633.html

第二种解释:

抽象类定义: 它的作用就是产生子类的同时给于子类一些特定的属性和方法。 abstract修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用abstract修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。

特性: 1.抽象类不能被实例化; 2.抽象类可以包含抽象方法和抽象访问器; 3.不能用sealed修饰符修改抽象类,这意味着抽象类不能被继承; 4.从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实现。

总结: ~抽象方法是隐式的虚方法; ~只容许在抽象类中使用抽象方法声明; ~因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号“{}”,实现由一个重方法提供,此重方法是非抽象类的成员; ~在抽象方法声明中使用static或virtual修饰符是错误的; ~除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样; ~在静态属性上使用absteact修饰符是错误的;

~在派生类中,通过包括使用override修饰符的属性声明,可以重写抽象的继承属性。

view plaincopy to clipboardprint? using System;
abstract class A
{
public abstract void F();
protected int _x;
public abstract int X
{
get;
set;
}
}
class B:A
{
public override void F()
{

}   
public override int X   
{   
    get{return _x;}   
    set{_x=value;}   
}   

}
class Test
{
static void Main()
{
B b=new B();
b.X=10;
Console.Write(b.X);
}
}
[c-sharp] view plain copy using System;
abstract class A
{
public abstract void F();
protected int _x;
public abstract int X
{
get;
set;
}
}
class B:A
{
public override void F()
{

}  
public override int X  
{  
    get{return _x;}  
    set{_x=value;}  
}  

}
class Test
{
static void Main()
{
B b=new B();
b.X=10;
Console.Write(b.X);
}
}

虚方法定义: 简单的说,虚方法就是可以被子类重写的方法,如果子类重写了虚方法,那么运行时将使用重写后的逻辑,如果没有重写,则使用父类中虚方法的逻辑; virtual关键字用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。

view plaincopy to clipboardprint? using System ;

class A

{

public void F( )
{
Console.WriteLine("A.F") ;
}

public virtual void G( )
{
Console.WriteLine("A.G") ;
}

}

class B: A

{

new public void F( )
{
Console.WriteLine("B.F") ;
}

public override void G( )
{
Console.WriteLine("B.G") ;
}

}

class Test

{

static void Main( )

{
B b = new B( ) ;

A a = b;

a.F( ) ;

b.F( ) ;

a.G( ) ;

b.G( ) ;

}

} 输出是:A.F B.F B.G B.G
[c-sharp] view plain copy using System ;

class A

{

public void F( )
{
Console.WriteLine("A.F") ;
}

public virtual void G( )
{
Console.WriteLine("A.G") ;
}

}

class B: A

{

new public void F( )
{
Console.WriteLine("B.F") ;
}

public override void G( )
{
Console.WriteLine("B.G") ;
}

}

class Test

{

static void Main( )

{
B b = new B( ) ;

A a = b;

a.F( ) ;

b.F( ) ;

a.G( ) ;

b.G( ) ;

}

} 输出是:A.F B.F B.G B.G

其实最重要的就是抽象方法不能实例化,要子类必须强制性的覆盖它的方法 。而虚方法则是提供了选择,可以覆盖可以不覆盖,继承基类中的虚方法。

总结比较如下:

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

~抽象方法和虚方法的区别在于:虚拟方法有一个实现部分,并为派生类提供了覆盖该方法的选项,相反,抽象方法没有提供实现部分,强制派生类覆盖方法(否则 派生类不能成为具体类); ~abstract方法只能在抽象类中声明,虚方法则不是; ~abstract方法必须在派生类中重写,而virtual则不必; ~abstract方法不能声明方法实体,虚方法则可以。