cnblogs/dcrenl/C#中virtual和abstract的区别.html
2024-09-24 12:43:01 +08:00

86 lines
6.5 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p>解读一</p>
<p>c# 中 Abstract和Virtual比较容易混淆都与继承有关并且涉及override的使用。下面讨论一下二者的区别</p>
<p><strong>一、Virtual方法虚方法</strong></p>
<p>  virtual 关键字用于在基类中修饰方法。virtual的使用会有两种情况<br /><br />  情况1在基类中定义了virtual方法但在派生类中没有重写该虚方法。那么在对派生类实例的调用中该虚方法使用的是基类定义的方法。<br /><br />  情况2在基类中定义了virtual方法然后在派生类中使用override重写该方法。那么在对派生类实例的调用中该虚方法使用的是派生重写的方法。</p>
<p><strong>二、Abstract方法抽象方法</strong></p>
<p>abstract关键字<strong>只能用在抽象类中修饰方法</strong>并且没有具体的实现。抽象方法的实现必须在派生类中使用override关键字来实现。<br /><br />接口和抽象类最本质的区别:<strong>抽象类是一个不完全的类,是对对象的抽象,而接口是一种行为规范。</strong></p>
<p><br /><strong>三、关键字</strong></p>
<p><strong>Static</strong>当一个方法被声明为Static时这个方法是一个静态方法编译器会在编译时保留这个方法的实现。也就是说这个方法属于类但是不属于任何成员不管这个类的实例是否存在它们都会存在。就像入口函数Static void Main因为它是静态函数所以可以直接被调用。</p>
<p><strong>Virtua</strong>当一个方法被声明为Virtual时它是一个虚拟方法直到你使用ClassName variable = new ClassName();声明一个类的实例之前,它都不存在于真实的内存空间中。这个关键字在类的继承中非常常用,用来提供类方法的多态性支持。</p>
<p>overrride表示重写 这个类是继承于Shape类<br />virtualabstract是告诉其它想继承于他的类 你可以重写我的这个方法或属性,否则不允许。<br />abstract抽象方法声明使用是必须被派生类覆写的方法抽象类就是用来被继承的可以看成是没有实现体的虚方法如果类中包含抽象方法那么类就必须定义为抽象类不论是否还包含其他一般方法抽象类不能有实体的。</p>
<p><em>a)&nbsp;&nbsp;&nbsp;&nbsp; virtual修饰的方法必须有方法实现(哪怕只有一对大括号),abstract修饰的方法不能有实现。</em></p>
<p>b)&nbsp;&nbsp;&nbsp; virtual可以被子类重写,abstract必须被子类重写</p>
<p>c)&nbsp;&nbsp;&nbsp;&nbsp; 如果类中的某一函数被abstact修饰,则类名也必须用abstact修饰</p>
<p>d)&nbsp;&nbsp;&nbsp; Abstract修饰的类不能被创建实例。</p>
<p>e)&nbsp;&nbsp;&nbsp;&nbsp; C#中如果准备在子类重写父类的方法则该方法在父类中必须用virtual修饰在子类中必须用overide修饰避免了程序员在子类中不小心重写了父类父类方法。</p>
<p>用abstract修饰的类只能被继承不能够被实例化。</p>
<p>解读二</p>
<p>virtual和abstract都是用来修饰父类的通过覆盖父类的定义让子类重新定义。</p>
<p>它们有一个共同点如果用来修饰方法前面必须添加public要不然就会出现编译错误虚拟方法或抽象方法是不能私有的。毕竟加上virtual或abstract就是让子类重新定义的而private成员是不能被子类访问的。</p>
<p>但是它们的区别很大。virtual是&ldquo;虚拟的&rdquo;abstract是&ldquo;抽象的").</p>
<p><strong>(1)virtual修饰的方法必须有实现哪怕是仅仅添加一对大括号),而abstract修饰的方法一定不能实现。</strong>如对于virtual修饰的方法如果没有实现</p>
<div>
<pre>public class Test1
{
public virtual void fun1();
}
</pre>
</div>
<p>错误:&ldquo;Test1.fun1()&rdquo;必须声明主体,因为它未标记为 abstract、extern 或 partial &nbsp;&nbsp;</p>
<p>对于abstract修饰的方法如果有实现</p>
<div>
<pre>public abstract class Test2
{
public abstract void fun2() { }
}
</pre>
</div>
<p>错误: &ldquo;Test2.fun2()&rdquo;无法声明主体,因为它标记为 abstract&nbsp;&nbsp;&nbsp;</p>
<p><strong>2virtual可以被子类重写而abstract必须被子类重写。</strong></p>
<div>
<pre>class BaseTest1
{
public virtual void fun() { }//必须有实现
}
class DeriveTest1:BaseTest1
{
//public override void fun() { }
}
</pre>
</div>
<p>编译不会出现错误如果重写了virtual修饰的方法前面必须添加override这样就告诉了编译器你要重写虚拟方法而且必须有实现否则编译出错</p>
<div>
<div>&nbsp;</div>
<pre>abstract class BaseTest2
{
public abstract void fun();
}
class DeriveTest2 : BaseTest2
{
//public override void fun();错误1:没有实现
//public void fun() { } 错误2重写时没有添加override
//override void fun() { }错误3虚拟成员或者抽象成员不能是私有的只要在父类中声明了虚拟成员或抽象成员即便是继承的也要加上这个限制
public override void fun() { }//如果重写方法; 错误:&ldquo;A.DeriveTest2&rdquo;不实现继承的抽象成员&ldquo;A.BaseTest2.fun()&rdquo;
}
</pre>
</div>
<p><strong>(3)如果类成员被abstract修饰则该类前必须添加abstract因为只有抽象类才可以有抽象方法。</strong></p>
<p><strong>(4)无法创建abstract类的实例只能被继承无法实例化</strong>,比如:&nbsp;&nbsp;&nbsp;&nbsp; BaseTest2 base2 = new BaseTest2();将出现编译错误:抽象类或接口不能创建实例。</p>
<p><strong>(5)C#中如果要在子类中重写方法必须在父类方法前加virtual在子类方法前添加override,这样就避免了程序员在子类中不小心重写了父类方法。</strong></p>
<p><strong>(6)abstract方法必须重写virtual方法必须有实现(即便它是在abstract类中定义的方法)。</strong></p>
<div>
<pre>abstract public class Test
{
//public virtual void Prinf();错误:virtual方法必须有实现
public virtual void Prinf() //abstract类的virtual方法可以不重写abstract方法必须重写。
{
Console.WriteLine("Abstract Printf...");
}
}
public class Class1 : Test
{
}</pre>
</div>