CLR学习笔记--深入理解多态机制

本文详细探讨了.NET Common Language Runtime (CLR) 如何实现多态机制,从多态的概念、类型对象和对象实例的创建过程,以及方法槽表在类型对象中的角色进行分析。重点在于理解JIT编译时如何处理虚方法和非虚实例方法,以及多态调用的本质。文章指出,多态的核心是通过类型对象地址加上槽偏移来调用方法,这种机制在运行时能够根据实际对象的类型动态决定调用哪个方法。
摘要由CSDN通过智能技术生成
一、引言

所谓万事开头难,哪怕是写一个学习笔记,以前看惯别人写的博客文章,当时看了就看了,只有一种感觉就是解决了心中的好久疑团,现在自己去写才了解,也许你看了只有短短几分钟,可别人却下了功夫,用了很多心,在此对那些分享文章的朋友表示敬意,想把自己理解的东西写出来十分不易,何况自己可能对写的东西也不自信,害怕自己的错误理解影响了别人,这是十分罪过的,费话不多说,在此表示,在此写的只是自己在学习的过程中自己的一些理解,只作为自己的学习笔记。

此次主要想把自己对多态机制的一些理解心得写下,写此文之前有看过网上的一篇关于讲多态机制的一篇文章,此笔记有多处是借鉴其博文内容,但是我为了使得自己理解更清楚,加了许多自己的理解

参考博文:http://www.cnblogs.com/qianyz/archive/2011/11/04/2235237.html

二、多态的概念

关于继续和多态的概念,各种资料和书籍中都有各样的解释,因为OO的概念并不是微软一个人提出来的,所以对于多态的概念没有一个确定的定义

MSDN 上面的定义:通过继承,一个类可以有多种类型:可以用作它自己的类型,任何基类型,或者在实现接口时用作任何接口的类型。

三、CLR如何创建运行时对象

在讲多态性之前,我们觉得有必要了解了一下CLR是如何创建运行时对象,对于CLR创建运行对象的全部过程很复杂,在此不打算细说,但不影响我们去了解多态的机制,在此我主要理解几个重要的概念和环节就可以,具体想深入的去了解.NET框架内部CLR如何创建运行时对象,参见http://www.microsoft.com/china/MSDN/library/netFramework/netframework/JITCompiler.mspx?mfr=true

 

在此,我们需要了解下面两个概念:类型对象和对象实例:

 

类型对象:类型对象是类型本身如(Object、String等),JIT在编译一段代码之前会检查这段代码中用到的所有类型,并且会在GC堆中检索这些类型对象是否已在GC堆中创建,如果没有,则会在GC堆中为其分配内存,并创建类型对象,在创建类型对象的过程里包括对类型对象中方法槽表创建,类型对象主要包括,类型对象指针、同步块索引、静态字段、方法表,在此要说明的是,类型对象的创建发生在JIT编译时期.

对象实例:某个具体类型对象的实例,一般通过new的方式在GC中创建,创建的过程主要包括初始化实例字段,对象类型创建后包括:类型对象指针、同步块索引、实例字段,其中类型对象指针指向对应的类型对象,具体new的过程参见CLR VIA C#第三版中的介绍,在此我又要说明的是,对象实例的创建发生在运行期.


在此我们可以知道对于所有的引用类型的实例对象(包括本身的类型对象),都包括类型对象指针和同步块索引.

对于对象实例来讲,类型对象指针指向的是对应的类型对象

对于类型对象来本身来讲,类型对象指针指向的是System.Type,其实类型对象我们其实也可以把当作视作为一个对象

在此对于同步块索引,这里暂不讨论

因此理解上面的两个概念后,我们知道对于所有形为的描述(方法)都是放在类型对象中的方法糟表中。

注意:

1、 对于对象实例,类型对象指针(TypeHandle)在有些文章中称为方法表指针,在此文中都称为类型对象指针

2、  对于类型对象,如BaseClass类型对象,在有些文章中称为BaseClass方法表,在此文中都称为类型对象,因为称为BaseClass方法表 从名称很容易让人误解,以为整这个类型对象都是一个方法列表,其实类型对象除了方法表,还有很多其他的内容

3、  对于类型对象中的方法表,在此文中都称为方法槽表(Method Slots Table)

类型对象与对象实例的创建过程:

以下面的一段代码和图表说明:

    public class BaseClass
    {
        public virtual void VirtualMethod()
        {
            Console.WriteLine("BaseClass VirtualMethod");
        }
        public static void StaticMethod()
        {
            Console.WriteLine("BaseClass StaticMethod");
        }
        public void InstanceMethod()
        {
            Console.WriteLine("BaseClass InstanceMethod");
        }
    }


                                                                                        图-1


过程分析:

1、 JIT编译时,注意是J IT编译时,遇到BaseClass Instance=new BaseClass();这行代码时,会先检查GC堆中是否已加载该类型对象,如无未加载,则计算并分配内存,并加载BaseClass类型,构建BaseClass类型对象,且该类型对象中记录了方法槽表,静态字段等。

2、 在JIT编译器生成汇编代码后,运行时,new一个BaseClass类型对象的实例时,计算分配内存,初始实例字段(包括基类的所有实例字段),并将类型对象指针指向BaseClass类型对象,并返回对象实例地址给栈上的Instance

对于JIT编译期创建类型对象的过程中,我们主要要关心的是,类型对象中方法槽表的创建机制,这里马上要讲到我们的核心内容,方法槽表.

方法糟表

方法槽表就是类型对象中的记录方法描述的那一部分,以图1为例的话,方法表就是图1的橙色区域.

为了更好分析,我们再看一个更详细结构图,如图2:



                                                                                     图-2

图2中的白色区域代表着一个类型对象的方法槽表,方法槽表里面记录着类型对象拥有的所有方法,对于这个方法槽表的创建过程,我们可按下面的顺序去了解:

1、  JIT加载类型对象

2、  遍历基类的虚方法(检查基类的virtual)并复制到方法糟表中

3、  检查类型对象是否对基类的虚方法是否有重写(检查override),如有重写则覆盖对应的虚方法

4、  添加类型对象自已新增加的虚方法(检查virtual)

5、  添加类型对象的构造方法(.ctor)

6、  添加类型对象的静态方法(检查static)

7、  添加类型对象的实例方法

方法糟表内存布局和层次结构:

观察图1和图2方法槽表的结构后,我们很容易发现,在图1和图2的方法槽表中,前4个方法都是Object类型对象中的4个虚方法,结合方法槽表的创建过程及顺序,我们大概可以知道一个类型对象中的方法槽表的内存布局了。

方法槽表的内存布局规则:类型对象永远是按照:基类虚方法—子类虚方法—构造方以—静态方法—实例方法

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值