在面向对象编程中,有两种截然不同的继承方式:实现继承和接口继承。在实现继承时候,在Java中,所有函数默认都是virtual的,而在C#中所有函数并不默认为virtual的,但可以在基类中通过声明关键字virtual,就可以在其派生类中通过关键字override重写该函数。
重写后的virtual函数依旧是virtual函数。由于virtual只对类中的实例函数成员有意义,所以成员字段和静态函数都不能声明为virtual,也不能与override和abstract一起用。C#中可以设置virtual属性、索引器或事件,例如
virtual string Name
{
get;
set;
}
无virtual和override关键字“重写”
如果签名后的函数在基类中都进行了声明,却没有用virtual和override关键字,例如:
class Base1
{
public void printMethod()
{
Console.WriteLine("base1");
}
}
class Derived1 : Base1
{
public void printMethod()
{
Console.WriteLine("derived1");
}
}
class Program
{
static void Main(string[] args)
{
Base1 base1 = new Base1();
Derived1 derived = new Derived1();
base1.printMethod();
derived.printMethod();
base1 = new Derived1();
base1.printMethod();
Console.ReadLine();
}
}
输出为:
base1
derived1
base1
由于方法相同,在用子类新方法编译代码时候,程序在应该调用哪种方法上就会有潜在的冲突,此时编译器会发出警告,认为子类Derived1的printMethod()隐藏了父类Base1的printMethod();此时可以从新命名子类Derived1的printMethod(),这是最好的解决办法,其次可以通过关键字new隐藏此方法来控制版本。
这是所谓的无virtual和override的“重写”其实只是隐藏。
有virtual和override关键字“重写”
在派生类中添加关键字virtual和override,实现对基类的重写:
class Base1
{
public virtual void printMethod()
{
Console.WriteLine("base1");
}
}
class Derived1 : Base1
{
public override void printMethod()
{
Console.WriteLine("derived1");
}
}
class Program
{
static void Main(string[] args)
{
Base1 base1 = new Base1();
Derived1 derived = new Derived1();
base1.printMethod();
derived.printMethod();
base1 = new Derived1();
base1.printMethod();
Console.ReadLine();
}
}
此时,输出的结果是:
base1
derived1
derived1
在类的定义中,申明时定义的类叫申明类,执行实例化时候定义的类叫实例类。例如:
Base1 base1 = new Derived1 ();其中Base1叫做申明类,而Derived1则是实例类。
此时编译器具体的检查的流程如下
1、当调用函数时,系统会直接去检查申明类,看所调用的函数是否为虚函数;
2、如果不是,那么它就直接执行该函数。如果是virtual函数,则转去检查对象的实例类。
3.在实例类中,若有override的函数,则执行该函数,如果没有,则依次上溯,按照同样步骤对父类进行检查,知道找到第一个override了此函数的父类,然后执行该父类中的函数。(星梦《C#虚函数virtual详解收藏》)
由此可知,
若子类Derived1中未添加关键字override,则直接在base1中执行父类同名函数,此时输出结果为:
base1
derived1
base1
依次类推,若有Derived2继承了Derived1,即:
class Derived2 : Derived1
{
public void printMethod(){
Console.WriteLine("derived2");
}
}
在Program类 中执行
base1 = new Derived2();
base1.printMethod();
则此时执行的是Derived2中override的同名函数printMethod()。