重写,隐藏,抽象,多态

  • virtual 用在基类中,指定一个虚方法(属性),表示这个方法(属性)可以重写。
  • override 用在派生类中,表示对基类虚方法(属性)的重写。

以上的基类和派生类都是相对的。B 是 C 的基类,也可以是 A 的派生类,B 中既可以对 A 中的 virtual 虚方法用 override 重写,也可以指定 virtual 虚方法供 C 重写。

  • 不能重写非虚方法或静态方法。重写的基方法必须是 virtual、abstract 或 override 的。为什么 override 也可以重写呢?因为基类中的 override 实际上是对基类的基类进行的重写,由于继承可传递,所以也可以对基类中 override 的方法进行重写。
  • override 声明不能更改 virtual 方法的可访问性。override 方法和 virtual 方法必须具有相同的访问级别修饰符。
  • 不能使用修饰符 new、static、virtual 或 abstract 来修改 override 方法。
  • 重写属性声明必须指定与继承属性完全相同的访问修饰符、类型和名称,并且被重写的属性必须是 virtual、abstract 或 override 的。
public class BaseClass
{
public virtual string GetString()
{
return "这是一个虚方法。";
}
}
public class DerivedClass : BaseClass
{
public override string GetString()
{
return "这是重写了的方法。";
}
}
 
 

public class BaseClass
{
public string GetString()
{
return "这是基类的一个方法。";
}
}
public class DerivedClass : BaseClass
{
public new string GetString()
{
return "这是隐藏了基类 GetString() 的方法。";
}
}

可以看出隐藏使用的是关键字 new

 

 

 

我们在分析问题时,越往上分析,就感觉结构越抽象。比如,我们分析动物的捕猎行为:这几种动物是群力合作,那几种动物是耐心守候,那几种动物是致命一击……他们都有一个方法叫“捕猎”,只是我们无法给他们一个统一的过程。此时我们可以在他们的基类中定义一个抽象方法,该方法什么事也不做,只是占个名字。

public abstract class HuntingAnimal
{
public abstract void Hunt();
}
public class Tiger : HuntingAnimal
{
public override void Hunt()
{
//...
}
}

HuntingAnimal 用 abstract 定义了一个抽象方法 Hunt(),由于抽象方法不做什么事情,所以不需要大括号,直接加引号结束即可。在派生类中,用 override 来实现这个抽象方法。

  • 抽象的类不能被实例化,所以不能用 new 来产生实例。
  • 如果方法是抽象的,则类必须是抽象的。
  • 派生类必须实现基类中的所有抽象方法,如果它不能做到,那么它也应该是个抽象类。
  • 抽象类不能是密封的。(关于密封:如果我们不想让一个类被继承,可以使用 sealed 关键字来确保它不会被继承。)

注意,虽然虚方法和抽象方法均是利用 override 关键字来重写,但虚方法和抽象方法是完全不同的。

 

 

一般我们指的多态性是指“运行时的多态性”,也就是在程序运行时,系统根据不同的对象确定调用对象所属类的相应方法的能力。

示例

namespace Cftea
{
public class BaseClass
{
public virtual string GetStringVirtual()
{
return "基类虚方法。";
}
public string GetString()
{
return "基类方法。";
}
}
public class DerivedClass : BaseClass
{
public override string GetStringVirtual()
{
return "派生类重写方法。";
}
public new string GetString()
{
return "派生类隐藏方法。";
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
DerivedClass derivedClass = new DerivedClass();
BaseClass baseClass = derivedClass;
MessageBox.Show("derivedClass.GetStringVirtual() 结果是:" + derivedClass.GetStringVirtual() +
"\r\n" +
"baseClass.GetStringVirtual() 结果是:" + baseClass.GetStringVirtual() + "\r\n" +
"derivedClass.GetString() 结果是:" + derivedClass.GetString() + "\r\n" +
"baseClass.GetString() 结果是:" + baseClass.GetString());
}
}
}

运行结果是:

c-sharp多态性演示结果

我们可以看到,derivedClass 与 baseClass 类型不同,但是指向的都是 new DerivedClass():

  • 他们在调用 GetStringVirtual() 时,使用的都是派生类的。(多态性)
  • 他们在调用 GetString() 时,使用的是各自类型所在的方法。

从这里我们可以看出重写与隐藏的区别了。

 

posted @ 2008-09-22 14:32  不染丹心  阅读(328)  评论(0编辑  收藏  举报