zoukankan      html  css  js  c++  java
  • 用C表达面向对象语言的机制2——颠覆你对方法调用的看法!

    用C表达面向对象语言的机制2——颠覆你对方法调用的看法!

    源代码在文末。推荐阅读本文PDF版,格式更好看。

    在上一篇《用C表达面向对象语言的机制——C#版》中,我们获知了如何用C表达面向对象语言的机制,证明了面向对象语言是对面向过程语言的封装。今天有幸看到《颠覆你对方法调用的看法!》,于是继续用C来模拟此文中的代码,看看“颠覆”的背后是什么。

    1. 目标

    本文展示用C的union来模拟C#的一些代码的写法。

    2. 用union代替FieldOffset

    例如如下的C#代码。

    Manager

    如果想用C来实现类似的使用方式,应该如何写呢?

    1) 用union代替FieldOffset

    用C的union代替FieldOffset等属性。

    FrancisYoungBase
    FrancisYoungDerived
    FrancisYoungManager


    就是说,union实现了将父类和子类指针都指向父类的实例的功能。

    2) 使用Manager类

    C#版的Manager,其典型的使用方式如下。

    Manager m = new Manager();
    m.derived.Print();// In Derived

    对应的C代码是什么样的?

    FrancisYoungManager * m = NewFrancisYoungManager();
    Print4FrancisYoungDerived(m->obj.pDerived);/* In Derived */

    与C#版的使用方法异曲同工。
    从C版代码可以看到,编译器根据pDerived的类型,选择了调用pDerived的类型中的方法。观察对C#转换为C的代码,可以发现,本质上同名的Print方法,对编译器而言的代号是不同的,所以编译器根据pDerived的类型,可以立即确定调用哪个方法。

    3. 变为虚函数之后

    下面展示将上文中的函数变为虚函数后的处理。

    C#代码如下。

    FrancisYoungManagerVirtual

    3) 用函数指针代替虚函数

    仍然用上一篇文章的方法,用函数指针来实现虚函数的功能。

    FrancisYoungBaseVirtual
    FrancisYoungDerivedVirtual
    FrancisYoungManagerVirtual

    4) 使用ManagerVirtual类

    C#代码的调用方式如下。

    ManagerVirtual m = new ManagerVirtual();
    m.derived.Print();// In Base

    对应的C代码如下。

    FrancisYoungManagerVirtual * m = NewFrancisYoungManagerVirtual();
    FrancisYoungBaseVirtual * pBase = (FrancisYoungBaseVirtual*)Convert2Type(m->obj.pDerived->metaInfo, FrancisYoungBaseVirtualTypeId);
    pBase->pPrint4FrancisYoungBaseVirtual(pBase);

    仍然与之神似。

    我们知道,虚方法在C代码中,变成了一个函数指针。根据上一篇文章的分析,我们在这里创建的是父类的对象,所以Print的函数指针指向的是父类的Print方法,即C版代码中的Print4FrancisYoungBaseVirtual方法。所以derived调用的只能是父类的Print4FrancisYoungBaseVirtual方法。

    4. 结论

    对《颠覆你对方法调用的看法!》的分析结果和原作者是一样的,这也印证了我们上一篇文章的结论的正确性。

    感想

    上一篇文章我提到,为什么要把C封装为面向对象语言?面向对象语言是如何从无到有的?最开始的那个人是怎么设计出这样一套机制的?他之前没有面向对象的任何概念,他的思路是什么?

    通过本文的分析,我的感觉是,面向对象语言的创始人一定是在大量的编写面向过程语言代码的时候,逐渐感受到了现实世界和程序语言的严重脱节,也发现了两者之间可能靠近一些的途径。一个函数写出来,如果几乎不可能被其他人用在其他地方,那应该把它隐藏起来,这就是封装的思想。

    而继承的思想是如何产生的,我还是不得而知。

    源代码在这里

  • 相关阅读:
    集合:List接口的实现类(ArrayList、LinkedList、Vector)
    IDEA:断点调试
    集合:Collection接口(常用方法、遍历)
    cookie中不能存储特殊字符的解决方案
    js:ES6中的类和对象、构造函数和原型
    jq:尺寸、位置(尺寸&位置)
    jq:插件(瀑布流、图片的懒加载、全屏滚动)
    jq:效果(显示、隐藏、切换、淡入淡出效果、自定义动画)
    jq:样式操作(返回css样式属性的值、修改属性的值、设置样式的方法)
    js:client、scroll(client与scroll)
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/Write_CSharp_In_C_2_Strange_Method_Invoking.html
Copyright © 2011-2022 走看看