C# 虚函数virtual的使用

一.前言

  在使用C#开发的过程中,我们经常可以看到virtual关键字,这个关键字具体的使用场景是有类做实现继承,父类通过virtual设置虚方法,子类可以通过override来重写该方法。

二.编译原理

  一般函数在编译时就静态地编译到执行文件中,其相对地址在程序运行期间是不发生变化。虚函数在编译期间是不被静态编译的,它的相对地址是不确定的,它在运行期间根据对象实例来判断要调用的函数。

三.实例讲解

1.一般情况

  这是一般的类实现继承,A和B类,B类继承A类,在A类和B类中都同时有一个相同名字的方法,在执行时会有什么影响?

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

public class B : A
{
    public void Func()
    {
        Console.WriteLine("B");
    }
}

//调用
public static void Main(string[] args)
{
    A a = new A();
    B b = new B();

    a.Func();
    b.Func();

    a = new B();
    a.Func();
}

  输出的结果是。

A
B
A

  第一个输出的结果是A,这个是毫无疑问的。

  第二个输出的结果是B,这是根据什么判断的?B类继承A类,如果两个类有同名的方法,那子类就会隐藏掉父类的同名方法。在编译器也会提醒是隐藏继承成员的方法,有意为之的话,可以使用关键字new。

  第三个输出的结果是A。这里先讲一下类申明、实例类的定义,如A a = new B();A为申明类,B为实例类。一般情况下,所调用的方法都是在申明类中的。

 

2.使用virtual关键字

  在上面的例子第三个输出得知,实例化的对象去调用方法,如A a = new B(),且A、B类都有同名方法,一般情况下是调用申明类的方法。那其它情况就是有使用virtual关键字的情况了,使用了virtual关键字修饰的方法叫做虚方法。

  上面讲过使用了virtual关键字,编译器会对虚方法指向的地址做处理,具体检查流程如下。

  1.在调用对象的方法时,首先会判断该对象的申明类中的方法是否为虚方法,如果不是虚方法,那么就会直接调用。

  2.如果是虚方法,那么它就会检查它的实例类是否有重新实现这个虚方法(使用override关键字),如果有,就直接调用实例类这个重新实现的方法。如果没有,则依次上溯,按照同样步骤对父类进行检查,直到找到重新实现该虚方法的父类,并调用方法。

  例子:准备要使用的类。

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

public class B : A
{
    public override void Func()
    {
        Console.WriteLine("B");
    }
}

public class C : B
{

}

public class D : A
{
    public new void Func()
    {
        Console.WriteLine("D");
    }
}

  

//调用
public static void Main(string[] args)
{
    A c = new C();
    c.Func();
}

  输出结果是B。检查到申明类A的是虚拟方法,转去检查实现类C。C类没有重写(override)方法,转为检查C类的父类B类,B类有重写该方法,调用该方法。

  另外,没有使用override的情况。

//调用
public static void Main(string[] args)
{
    A d = new D();
    d.Func();
}

  输出结果是A。虽然实现类有Func,但由于没有(重写)override,还是会转去检查父类,最终检查回A类的话,就会直接调用这个virtual方法。

四.总结

  1.virtual关键字在实现继承的时候使用。

  2.在申明类定义了虚方法,那么它就会去判断实现类是否有重写(override)该方法,并调用之。

  3.延伸知识,在Java中,所有类的方法都是默认virtual。

 

posted @ 2021-03-12 17:34  shine声  阅读(1666)  评论(0编辑  收藏  举报