• C# 方法 虚方法的调用浅谈


    我们在面试中经常碰到有关多态的问题,之前我也一直被此类问题所困扰,闹不清到底执行哪个方法。

    先给出一道简单的面试题,大家猜猜看,输出是?

    View Code 
        public class A
        {
            public void MethodF() 
            { 
                Console.WriteLine("A.F"); 
            }
            public virtual void MethodG() 
            { 
                Console.WriteLine("A.G"); 
            }
        }
        public class B : A
        {
            new public void MethodF() 
            { 
                Console.WriteLine("B.F"); 
            }
            public override void MethodG() 
            { 
                Console.WriteLine("B.G"); 
            }
        }
        class Test
        {
            static void Main()
            {
                B b;
                b = new B();
                A a = b;
                a.MethodF();
                b.MethodF();
                a.MethodG();
                b.MethodG();
            }

    首先看一下虚方法的定义(MSDN):

      若一个实例方法的声明中含有 virtual 修饰符,则称该方法为虚拟方法。若其中没有 virtual 修饰符,则称该方法为非虚拟方法。

    以上面题目Test类Main中代码为例,简单说一下CLR创建对象的过程都做了什么事情

    1) 首先,声明一个引用类型变量 b,它仅是一个引用,保存在线程的栈上,用于将来存放B对象的有效地址。此时 b 未指向任何有效的实例,值为null,相关代码为:

         B b;

    2) 接下来,通过new执行对象的创建,即:

         b = new B();
    对象的实例保存在托管堆上,CLR在创建一个新对象的同时,还会创建它的类型对象(如果类型对象不存在)。

      对象实例在堆中的内存包括实例字段、类型对象指针、同步索引块,类型对象指针指向类型对象。

      类型对象在堆中分配的内存包括类型对象指针、同步索引块、静态字段、方法表。

    3)  A a = b;  这行代码首先声明一个类型为A的引用类型变量a,并将其实际地址指向b所指向的对象实例。

    4)  之后就是方法的调用,下面详细说一下C#中方法的调用:

        a.MethodF();

    当调用一个对象的方法时,会直接检查这个对象变量(a)的类型 ,找到堆中的类型对象,查看是否有该方法,没有则通过类型对象的类型对象指针向上回溯查找,直至找到,然后检查该方法是否为虚方法,如果非虚,直接调用,由于MethodF 方法是非虚的,因此直接调用输出A.F。

        a.MethodG();

    如果该方法为虚方法,即有virtual 关键字,则根据对象变量(a),去找到对象的实例类B,查找该类型对象中是否重新实现过该虚方法(override 关键字),如果有,OK执行,如果没有,向上检查其父类,直至找到然后执行,MethodG为虚方法,则会查找实例B,由于B中重写了MethodG,因此此处输出B.G


      通过上面的描述,开始的那道面试题,我们应该轻松可以得出输出,此处就不啰嗦了。 

      一般考多态的面试题中 virtual new override  几个关键字经常出现,new 关键字实现一个新的方法,同时隐藏基类的同名方法。 

     
     
  • 相关阅读:
    skynet源码分析之socketchannel
    skynet源码分析之master/salve集群模式
    skynet源码分析之网络层——网关服务器
    Android反编译基础(apktoos)--广工图书馆APK
    Android-Native-Server 启动和注册详细分析
    Android NDK r8 windows环境搭建
    Android 4.1.1源码编译
    Android Binder------ServiceManager启动分析
    更改系统盘符后DFS无法复制故障处理
    Centos6.9部署Gitlab-11.9.8并汉化
  • 原文地址:https://www.cnblogs.com/kdalan/p/2523470.html
Copyright © 2020-2023  润新知