今天看到这篇文章一个在C#以及类似的面向对象系統(Java中估计也是如此)中常见的错误,感触颇多,说句实在话,国内目前的OO语言教学中忽略了一个关键的一环“OO的对象模型”,这里有本好书:侯捷的《深度探索C++对象模型》。看过的与没有看过的,对理解OO的对象模型有层次的不同。看过的人往往会思考:“编译器到底做了什么”?没看过的会想当然:“应该是这样的,就是这样的......”。比如把一个子类对象强制转换为基类对象,其实编译器处理就是把该对象作为基类对象来处理(即对象的Slip)。当然调用的方法(非虚函数)也是基类的方法,和子类无关。而调用虚函数则先要去对象内存地址,再获取对应的vTable(在C++,Delphi中都是类似处理,根据对象的地址,获取该对象的vTable),再根据虚函数的偏移量获取vtable表中的实际虚函数的函数地址,从而实现OO的多态。

还是通过实例代码来解释吧

public class BaseClass
    {
        public string m_Name = "BaseClass";

        public void RealName()
        {
            Console.WriteLine(m_Name);
        }

        public virtual void VirtualName()
        {
            Console.WriteLine(m_Name);
        }
    }

    public class DerivedClass : BaseClass
    {
        public string m_Name = "DerivedClass";

        public void RealName()
        {
            Console.WriteLine(m_Name);
        }

        public override void VirtualName()
        {
            Console.WriteLine(m_Name);
        }
    }

    public class Class2
    {
        [STAThread]
        static void Main(string[] args)
        {
            BaseClass lBaseclass = new DerivedClass();
            lBaseclass.RealName();//return :  BaseClass 
            lBaseclass.VirtualName();//return :  DerivedClass
            Console.WriteLine("-----------------------");

            DerivedClass lDerivedClass = (DerivedClass)lBaseclass;
            lDerivedClass.RealName();//return :  DerivedClass
            lDerivedClass.VirtualName();//return :  DerivedClass
            Console.WriteLine("-----------------------");

            lBaseclass.m_Name = "ModifyByBase";
            lBaseclass.RealName();//return :  ModifyByBase
            lBaseclass.VirtualName();//return :  DerivedClass
            Console.WriteLine("-----------------------");

            lDerivedClass.m_Name = "ModifyByDerived";
            lDerivedClass.RealName();//return :  ModifyByDerived
            lDerivedClass.VirtualName();//return :  ModifyByDerived
            Console.WriteLine("-----------------------");


            lDerivedClass = new DerivedClass();
            ((BaseClass)lDerivedClass).RealName();//return :  BaseClass
            ((BaseClass)lDerivedClass).VirtualName(); //return :  DerivedClass            

            Console.ReadLine();
        }    

    }

上面第一段代码的内存布局如下图所述:

第二段的代码相对简单,只是把用lBaseClass指向的对象强制类型转换为子类对象,内存结构如下图所示:

第三段的代码的内存结构如下图所示:

第四段的代码的内存结构如下图所示:

第五段的内存如下图所示:

总之,大家要知道,等编译完成后,所有的属性访问或者函数调用都已经根据变量的声明类型都被确定了(访问哪个内存地址已经确定了),除了虚函数(晚绑定)...。

比如调用lBase.VirtualName()这个虚函数,编译器做的工作流程如下:
1,为BaseClass和DerivedClass的各个虚函数编号1(偏移量)
2,lBase.VirtualName()表示调用lBase对象的vtable指针(在C++,Delphi中都是类似处理,根据对象的地址,获取该对象的vTable)所指向的vTable表中的1号虚函数。
3,那么如果lBase实际是指向BaseClass创建的对象,那么就会调用BaseClass的VirtualName(),如果lBase实际是指向DerivedClass创建的对象,那么就会调用DerivedClass的VirtualName()。则就是多态。

这里以一句侯捷的话作为本文的结束语:“勿在浮沙筑高台”。

转载于:https://www.cnblogs.com/caomao/archive/2005/06/16/175459.html

希望这篇文章对理解C#的对象模型有所帮助相关推荐

  1. 如果你也在学python,准备要学习python,希望这篇文章对你有用。

    如果你也在学python,准备要学习python,希望这篇文章对你有用.虽然有点长,但是建议坚持看完! 首先 建议1.理解Pythonic概念--详见Python中的<Python之禅> ...

  2. 2.2基本算法之递归和自调用函数_你为什么学不会递归?读完这篇文章轻松理解递归算法...

    对于很多编程初学者来说,递归算法是学习语言的最大障碍之一.很多人也是半懂不懂,结果学到很深的境地也会因为自己基础不好,导致发展太慢. 可能也有一大部分人知道递归,也能看的懂递归,但在实际做题过程中,却 ...

  3. 可能存在无限递归_你为什么学不会递归?读完这篇文章轻松理解递归算法

    对于很多编程初学者来说,递归算法是学习语言的最大障碍之一.很多人也是半懂不懂,结果学到很深的境地也会因为自己基础不好,导致发展太慢. 可能也有一大部分人知道递归,也能看的懂递归,但在实际做题过程中,却 ...

  4. 彻底理解 SpringIOC、DI,这篇文章就够了

    前言 你可能会有如下问题: 1.想看Spring源码,但是不知道应当如何入手去看,对整个Bean的流程没有概念,碰到相关问题也没有头绪如何下手 2.看过几遍源码,没办法彻底理解,没什么感觉,没过一阵子 ...

  5. 来篇文章:Martin Fowler的设计已死中文版

    设计已死? 英文原文版权由Martin Fowler拥有 Original text is copyrighted by Martin Fowler Martin Fowler Chief Scien ...

  6. java中override快捷键_【基础回溯1】面试又被 Java 基础难住了?推荐你看看这篇文章。...

    本文已经收录自 https://github.com/Snailclimb/JavaGuide  (59k+ Star):[Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识. ...

  7. Java面试不通过?这篇文章你看了吗?

    文章目录 一.Java 基础 1.JDK 和 JRE 有什么区别? 2. == 和 equals 的区别是什么? 3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗 ...

  8. 准备开发一个智能硬件,得先看这篇文章!

    一个智能硬件生命周期内所需要经历的全部流程,以及产品经理需负责的相关工作分为以下各阶段, 我们一起看看这个过程有多长,又有哪些经验可以分享. 一.市场分析 如同互联网产品一样,除了在立项之前需要对市场 ...

  9. Python 这篇文章告诉我Python实际中干什么事情

    一直心存疑虑:Python可以干什么事情? 对Python在企业级开发中的10大误解 lyxi | 2015-10-15 10:49    浏览量(216)    评论(0)   推荐(0) 数据 在 ...

  10. 汽车保养知识知多少?这篇文章让你秒懂

    随着科技水平的发展,汽车的拥有量越来越多,汽车保养的知识又有多少人懂呢?这篇文章简单介绍下. 燃油滤清器 正常我们所说的三滤一般指机油滤清器,空气滤清器,空调滤清器这三种.燃油滤清器属于长效滤清器,不 ...

最新文章

  1. shell脚本的命令行传参
  2. Could not load dynamic library ‘cudart64_101.dll‘
  3. 转发和重定向和request域对象
  4. django定时任务
  5. 栈的应用--迷宫问题
  6. Hadoop学习笔记—10.Shuffle过程那点事儿
  7. 【Linux】查看日志文件
  8. java 在面板中加入标签_创建一个JTabbedPane面板,为每一个标签设置一个名称
  9. 源码分析Dubbo服务提供者启动流程-下篇
  10. OMNeT++ ALOHA sample代码阅读
  11. Django入门:第十一章、基础模板
  12. 强智教务系统模拟登陆经验【附源码】
  13. llama是什么动物_羊驼(Alpaca)与骆马(Llama)
  14. 调查:听取当前用户的意见(并改进),是为什么?
  15. 先进级!阿里云大数据+AI平台通过信通院数据平台整体解决方案最高等级评测
  16. python程序员专用壁纸_神级python程序员分享的让小白30分钟快速上手的一张神图,赶快收藏!...
  17. android 相机自动延时拍照软件,延时摄影大师app下载-延时摄影大师 安卓版v3.0-PC6安卓网...
  18. cm-14.1 Android系统定制(二):内置系统应用
  19. STL 大锅炖(一):什么是 STL
  20. 即时配送行业黑马 闪飞侠2022正式起航

热门文章

  1. php array sum 小数位,多维数组上的PHP Array_Sum
  2. java获取鼠标点击的坐标_怎么我用Java窗外获取鼠标点击的坐标
  3. gin--简单的登录界面的实现
  4. JSEclipse安装后无法打开js文件_如何在你的 PC 上 下载并配置 Node.js
  5. redis smembersmap_Redis五种数据类型
  6. locate命令详解
  7. 与Claudia.js的作者Gojko Adzic谈论如何通过Claudia将Node.js微服务部署至AWS Lambda
  8. Fork/Join 框架-设计与实现(翻译自论文《A Java Fork/Join Framework》原作者 Doug Lea)...
  9. 读取和导出下载 excel 2003,2007 资料
  10. centos6.5 vncserver安装与配置