zoukankan      html  css  js  c++  java
  • C++虚函数表

    大家知道虚函数是通过一张虚函数表来实现的。在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,其内容真是反应实际的函数。这样,在有虚函数的类的实例中,这个表分配在了这个实例的内存中,所以,当用父类的指针来操作一个子类的时候,这张虚函数表就显得尤为重要了。它就像一个地图一样,指明了实际所应该调用的函数。

    C++的标准规则中说到,编译器必须保证虚函数表的指针存在于对象实例中最前面的位置(这样是为了保证正确取到虚函数的偏移量)。这意味着通过对象实例的地址得到这张虚函数表,然后可以遍历其中的函数指针,并调用相应的函数。

     

    #include <iostream>
    using namespace std;
    class Base
    {
    public:
        virtual void fun1(){cout<<"Base::fun1
    ";}
        virtual void fun2(){cout<<"Base::fun2
    ";}
        virtual void fun3(){cout<<"Base::fun3
    ";}
    private:
        int num1;
        int num2;
    };
    
    typedef void (*Fun)(void);
    
    int main()
    {
        Base b;
        Fun pFun;
        //通过指针分别调用了对象b的3个虚函数。
        pFun = (Fun)* ( (int*)*(int*)(&b)+0 );
        pFun();
        pFun = (Fun)* ( (int*)*(int*)(&b)+1 );
        pFun();
        pFun = (Fun)* ( (int*)*(int*)(&b)+2 );
        pFun();
        return 0;
    }
    /*
    程序执行结果如下:
    Base::fun1
    Base::fun2
    Base::fun3
    Press <RETURN> to close this window...
    */

    程序中的Base对象b内存结构如下:

    Image-1_thumb2_thumb


    一个类会有多少张虚函数表呢?

    对于一个单继承的类,如果它有虚函数,则只有一张虚函数表。对于多重继承的类,它可能有多张虚函数的表。

    #include <iostream>
    using namespace std;
    class Base1
    {
    public:
        Base1(int num):num_1(num){}
        virtual void fun1(){cout<<"Base1::fun1 "<<num_1<<endl;}
        virtual void fun2(){cout<<"Base1::fun2 "<<num_1<<endl;}
        virtual void fun3(){cout<<"Base1::fun3 "<<num_1<<endl;}
    private:
        int num_1;
    };
    class Base2
    {
    public:
        Base2(int num):num_2(num){}
        virtual void fun1(){cout<<"Base2::fun1 "<<num_2<<endl;}
        virtual void fun2(){cout<<"Base2::fun2 "<<num_2<<endl;}
        virtual void fun3(){cout<<"Base2::fun3 "<<num_2<<endl;}
    private:
        int num_2;
    };
    class Base3
    {
    public:
        Base3(int num):num_3(num){}
        virtual void fun1(){cout<<"Base3::fun1 "<<num_3<<endl;}
        virtual void fun2(){cout<<"Base3::fun2 "<<num_3<<endl;}
        virtual void fun3(){cout<<"Base3::fun3 "<<num_3<<endl;}
    private:
        int num_3;
    };
    class Derived1:public Base1
    {
    public:
        Derived1(int num):Base1(num){}
        virtual void fDer1_1(){cout<<"Derived1::fDer1_1
    ";}//无覆盖
        virtual void fDer1_2(){cout<<"Derived1::fDer1_2
    ";}
    };
    class Derived2:public Base1
    {
    public:
        Derived2(int num):Base1(num){}
        virtual void fun2(){cout<<"Derived2::fun2 "<<endl;}//只覆盖了Base1::fun2
        virtual void fDer2_1(){cout<<"Derived2::fDer2_1
    ";}
        virtual void fDer2_2(){cout<<"Derived2::fDer2_2
    ";}
    };
    class Derived3:public Base1,public Base2,public Base3//多重继承,无覆盖
    {
    public:
        Derived3(int num_1,int num_2,int num_3):Base1(num_1),Base2(num_2),Base3(num_3){}
        virtual void fDer3_1(){cout<<"Derived3::fDer3_1
    ";}
        virtual void fDer3_2(){cout<<"Derived3::fDer3_2
    ";}
    
    };
    class Derived4:public Base1,public Base2,public Base3//多重继承,有覆盖
    {
    public:
        Derived4(int num_1,int num_2,int num_3):Base1(num_1),Base2(num_2),Base3(num_3){}
        virtual void fun1(){cout<<"Derived4::fun1
    ";}//覆盖了所有基类的fun1函数
        virtual void fDer4_1(){cout<<"Derived4::fDer4_1
    ";}
    
    };
    int main()
    {
        Base1 *pBase1 = NULL;
        Base2 *pBase2 = NULL;
        Base3 *pBase3 = NULL;
    
        cout<<"-----  Generally inherited from Base1, no cover------
    ";
        Derived1 d1(1);
        pBase1 = &d1;
        pBase1->fun1();
    
        cout<<"----- Generally inherited from Base1, covering fun2---
    ";
        Derived2 d2(2);
        pBase1 = &d2;
        pBase1->fun2();
    
        cout<<"-----  Multiple inheritance, no cover-----------------
    ";
        Derived3 d3(1,2,3);
        pBase1 = &d3;
        pBase2 = &d3;
        pBase3 = &d3;
        pBase1->fun1();
        pBase2->fun1();
        pBase3->fun1();
    
        cout<<"-----  Multiple inheritance, covering fun1-------------
    ";
        Derived4 d4(1,2,3);
        pBase1 = &d4;
        pBase2 = &d4;
        pBase3 = &d4;
        pBase1->fun1();
        pBase2->fun1();
        pBase3->fun1();
        return 0;
    }
    
    /*
     * 程序运行结果如下:
    -----  Generally inherited from Base1, no cover------
    Base1::fun1 1
    ----- Generally inherited from Base1, covering fun2---
    Derived2::fun2
    -----  Multiple inheritance, no cover-----------------
    Base1::fun1 1
    Base2::fun1 2
    Base3::fun1 3
    -----  Multiple inheritance, covering fun1-------------
    Derived4::fun1
    Derived4::fun1
    Derived4::fun1
    Press <RETURN> to close this window...
    */

    一般继承(无虚函数覆盖)

    Derived1类继承自Base1类,没有任何覆盖基类的函数,因此Dervied1的两个虚拟函数被依次添加到了虚函数表的尾部。Derived1的虚函数表如下图:

    Image-2_thumb1_thumb


    一般继承(有虚函数的覆盖)

    Derived2继承自Base1类,并对基类中的fun2()进行了覆盖。所以虚函数表中的Derived2::fun2代替了Base::fun2,用时派生类中新的虚函数添加到虚函数的表尾。Derived2的虚函数表如下图:

    Image-2_thumb3_thumb


    多重继承(无虚函数覆盖)

    Derived3继承自Base1,Base2,Base3,其虚函数表如下:

    Image-3_thumb2_thumb1

    Derived3的每个父类都有自己的虚表,所以Derived3也就有了3个虚表。这里父类虚表的顺序与声明继承父类的顺序一致。这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。例如:

    Base2 *pBase2 = new Derived3();
    pBase->fun2();

    把Base2类型的指针指向Derived3实例,那么调用将是对应Base2虚表里的那些函数.


    多重继承(有虚函数覆盖)

    Derived4类继承自Base1,Base2,Base3并对3个基类的fun1函数进行了覆盖。其虚函数表如下:

    Image-3_thumb2_thumb

    可以看见基类中的fun1都被替换成了Derived4::fun1,这样,我们就可以把任意一个静态类型的父类指向子类,并调用子类的f()了。

    Base1 *pBase1 = new Derived4();
    pBase1->fun1();

  • 相关阅读:
    mydumper 备份工具
    k8s 二进制部署详解
    etcd+https部署
    Harbor + Https 部署
    Nginx+Tomcat+Memcache 实现session共享
    rap 部署
    Centos6.5下rsync+inotify的配置详解
    python2.7中MySQLdb的安装与使用详解
    Linux中普通用户提权为超级用户
    Mysql忘记密码
  • 原文地址:https://www.cnblogs.com/zi-xing/p/4443337.html
Copyright © 2011-2022 走看看