VIRTUAL函数成员
✦ 标记为virtual的函数可以被子类重写,包括方法、属性、索引器、事件
可以这么理解,
你看,
我们有了继承这个方式,
但是我还想改父类的东西,
怎么办?
那就设置一个关键词叫virtual吧!
只需要把virtual加在类型的前面,
举例:
public class Asset
{
public string Name;
public virtual decimal Liability=>0;
}
然后在子类里面重写
OVERRIDE重写
✦ 使用override修饰符,子类可以重写父类的函数
public class Stock:Asset
{
public long SharesOwned;
}public class House:Asset
{
public decimal Mortgage;
public override decimal Liability=>Mortgage;
}House mansion=new House{Name="McMansion",Mortgage=250000};
Asset a=mansion;
Console.WriteLine(mansion.Liability); //250000
Console.WriteLine(a.Liability); // 250000
关于Override(重写)的要求:
✦ virtual方法和重写方法的签名、返回类型、可访问程度必须是一样的
✦ 重写方法里使用base关键字可以调用父类的实现
注意:
✦ 在构造函数里调用virtual方法,可能比较危险,因为编写子类的开发人员,可能不知道他们在重写方法的时候,面对的是一个未完全初始化的对象。
✦ 换句话说,重写的方法可能会访问依赖于还未被构造函数初始化字段的属性或方法。
举例:
public class Parent
{
protected readonly string name;public Parent()
{
GetNameLength();
name = "MD";
}public virtual int GetNameLength()
{
return 0;
}}
public class Child : Parent
{
public override int GetNameLength()
{
return base.name.Length;
}
}class Program
{
static void Main(string[] args)
{
Child child = new Child();
child.GetNameLength();
}
}
报错:
System.NullReferenceException:“未将对象引用设置到对象的实例。”
name 是 null。
因为当子类实例child调用修改后的GetNameLength()时,父类的name字段初始化是在GetNameLength()之后的,
上述代码 在重写GetNameLength()方法中调用 未初始化的字段,所以抛出异常。
这就是
“重写的方法可能会访问依赖于还未被构造函数初始化字段的属性或方法”。
所以这给我们的启示是:
没事别去改别人的父类的方法,我知道别人的方法可能不适合你,所以你去别人的类里面添加了virtual关键词,
加virtual关键词是为了防止影响其他调用这个父类的方法,然后在自己的类里面重写。
我们可以明白的是,
virtual和override是相辅相成的,这两个关键词的出现,为不破坏架构式地修改父类方法和属性,提供了可能。