zoukankan      html  css  js  c++  java
  • 回答总结:C实现“动态绑定”

    C实现“动态绑定”

    2010-7-26

    烛秋

         在论坛上看到这样一个问题:“用C能实现C++的动态绑定吗?”网址:http://topic.csdn.net/u/20100624/21/3d7eda37-cbf7-4e36-a549-f2d6f1a3eeed.html?47092。。现在看当时我的回复(ID:wuxupeng999),觉得理解上还是有些不足,这里再总结一下。

      有网友给出了利用结构体和函数指针实现的方法。看了之后我觉得有点别扭,于是我自己再对动态绑定作了认真的理解,并做下总结。

    一、什么是动态绑定

      动态绑定就是某个对象要到程序执行时才知道是哪个对象。也就是说,最终编译成汇编指令的时候,可能是这样子的:"call [eax]",指令调用哪个函数,只有到程序执行的时候才会知道。在程序执行的时候,通过修改eax的值,使得程序调用不同的函数,这就是所谓的动态绑定。从汇编看来这是很平常的,例如,编写了一个函数,这个函数的入口参数eax是另一个函数地址,然后程序call [eax],这就动态了。当然也可以不用寄存器而用别的方式,例如call [地址a],地址a里边存放的值是某个函数的地址,修改地址a里的值就行了。

      我觉得对于汇编来说,动态就是修改call后边的寄存器/地址的值,对于C来说就是修改指针所指向的函数地址,而指针也就是保存函数地址的变量,还是跟汇编一样。C++的动态绑定是高级语言的说法了,C++的动态绑定可以说是基类指针指向子类对象,然后通过基类指针调用子类实现的函数。而对于C和汇编来说,也就是把某个保存地址的变量的值修改一下。从这一点来说,用C实现动态绑定,没有必要搞什么模拟虚函数、虚函数表,直接来个(void*)指针,然后让它指向不同的函数,不过在函数调用的时候C编译器必须知道函数原型,可以使用typedef。

    二、测试

    代码①

    /////////////////////////////////////////////////
    #include <stdio.h>
    #include <windows.h>
    int test_add(int a, int b);
    int test_sub(int a, int b);
    void    all(void *p);
    int main ()
    {
        /*定义一个void类型指针*/
        void *fp;
        /*指向test_add*/
        fp = (int*)test_add;
      printf("test test_add:\n");
        /*此时all执行test_add,输出7*/
        all(fp);
        /*指向test_sub*/
        fp = (int*)test_sub;
        printf("test test_sub:\n");
        /*此时all执行test_sub,输出-1*/
        all(fp);
        system("pause");
        return 0;
    }
    ////////////////////////////
    /*函数1*/
    int test_add(int a, int b)
    {
        return    a+b;
    }
    ////////////////////////////
    /*函数2*/
    int test_sub(int a, int b)
    {
        return    a-b;
    }
    ////////////////////////////
    /*依靠输入参数的不同,调用不同的函数。动态绑定*/
    void    all(void *p)
    {
        int    a = 3;
        int    b = 4;
        typedef    int    (*fp)(int a, int b);
        int c = ((fp)p)(3,4);
        printf("%d\n",c);
    }
    
    /*输出:
    test test_add:
    7
    test test_sub:
    -1
    Press any key to continue . . .
    */
    
      以我的理解我认为已经实现了动态绑定。对于all函数来说,入口参数p决定了它会调用哪个函数,只有到函数执行期间才能确定,这就是动态绑定。

    三、比较分析

           下面的代码是某网友用结构体和函数指针实现的:

    代码②

    /////////////////////////////////////////////////
    #include <stdio.h>
    /////////////////////////////////////////////////
    typedef struct base
    {
            void (*vfun)(void);
    }Base;
    
    typedef struct derived
    {
            Base b;
            void (*vfun)(void);
    } Derived;
    /////////////////////////////////////////////////
    void Bfun()
    {
         puts("Base vfcn");
    }
    
    void Dfun()
    {
         puts("Derived vfcn");
    }
    /////////////////////////////////////////////////
    void Baseconstruct(Base* b)
    {
         b->vfun=Bfun;
    }
    
    void Derivedconstruct(Derived* d)
    {
         d->b.vfun=Dfun;
         d->vfun=Dfun;
    }
    /////////////////////////////////////////////////
    int main(void)
    {
        Base ba,*pb;
        Derived de;
    
        Baseconstruct(&ba);
        Derivedconstruct(&de);
        ba.vfun();//正常调用
        de.vfun();
        pb = &ba;//动态调用
        pb->vfun();
        pb = (Base*)&de;
        pb->vfun();
        getchar();
        return 0;
    }
    /*
    Base vfcn
    Derived vfcn
    Base vfcn
    Derived vfcn
    */
    
    

      代码②用结构体模拟类,然后还搞出了构造函数,模拟了很多C++的外表,但是代码②没有办法采用真正的虚函数表,所以在结构体里边保存了两个同样的指针。

       这就是为什么需要:d->b.vfun=Dfun。“父类”(结构体)指针在调用vfun函数的时候,调用的结果就是这条指令的功劳。这里如果把Dfun改成其它的,那“父类”指针调用输出就是其它的了。这个“动态绑定”还是通过“子类”(结构体)对象来调用函数的。

      动态绑定其实没必要搞得那么复杂,动态绑定只是C++的一个功能而已,模仿了那么多,把一些不必要的东西也加上去了,反而混淆了动态绑定的根本。

  • 相关阅读:
    周末总结
    大数据开源框架技术汇总
    oracle迁移mysql总结
    梯度下降
    BFC的概念
    元素类型
    window10安装tensorflow
    学习使用git
    设计模式中的关系
    拟合圆
  • 原文地址:https://www.cnblogs.com/cswuyg/p/1804991.html
Copyright © 2011-2022 走看看