zoukankan      html  css  js  c++  java
  • C++多态中虚函数表合并与继承问题

    多态:

    C++的多态是通过一张虚函数表(Virtual Table)来实现的,简称为 V-Table。在这个
    表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆写的问题,保证其真实
    反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中
    所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,
    它就像一个地图一样,指明了实际所应该调用的函数

    这里我们着重看一下这张虚函数表。C++的编译器应该是保证虚函数表的指针存在
    于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有
    多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函
    数表,然后就可以遍历其中函数指针,并调用相应的函数

    以下代码运行结果,基于环境 X86_64 64位编译器。 

    虚函数表与与表指针

    #include <iostream>
    
    using namespace std;
    
    class Base {
    public:
    virtual void f() { cout << "Base::f" << endl; }
    virtual void g() { cout << "Base::g" << endl; }
    virtual void h() { cout << "Base::h" << endl; }
    int ba; }; typedef
    void(*FUNC)(); int main() { Base b; cout<<sizeof(b)<<endl; cout<<"Base_Addr:"<<(int*)(&b)<<endl; cout<<"VTalbe_Addr:"<<(int**)(int*)(&b)<<endl; FUNC pf = NULL; pf = (FUNC)*((int**)*(int*)(&b)+0); pf(); pf = (FUNC)*((int**)*(int*)(&b)+1); pf(); pf = (FUNC)*((int**)*(int*)(&b)+2); pf(); }

     

    运行结果:

     

     虚函数表排在一个类的最前面,虚函数在虚函数表中按声明顺序排列。

     

    派生类部分实现覆写:

    class Base {
    public:
      virtual void f() { cout << "Base::f" << endl; }
      virtual void g() { cout << "Base::g" << endl; }
      virtual void h() { cout << "Base::h" << endl; }
    };
    
    class Derived:public Base
    {
    public:
      virtual void f() { cout<<"Derived::f"<<endl; } }; typedef
    void(*FUNC)(); int main() { Derived b; cout<<sizeof(b)<<endl; cout<<"Base_Addr:"<<(int*)(&b)<<endl; cout<<"VTalbe_Addr:"<<(int**)(int*)(&b)<<endl; FUNC pf = NULL; pf = (FUNC)*((int**)*(int*)(&b)+0); pf(); pf = (FUNC)*((int**)*(int*)(&b)+1); pf(); pf = (FUNC)*((int**)*(int*)(&b)+2); pf(); }

    运行结果:

     

    单继承:

    父子中兼有虚函数

    class Base {
    public:
      virtual void f() { cout << "Base::f" << endl; }
      virtual void g() { cout << "Base::g" << endl; }
      virtual void h() { cout << "Base::h" << endl; }
    protected:
    //int b; };
    class Derived:public Base { public: virtual void d() { cout << "Derived::d" << endl; }

    };
    typedef void(*FUNC)();
    int main()
    {
        Derived d;
        cout<<sizeof(d)<<endl;
        cout<<"Base_Addr:"<<(int*)(&d)<<endl;
        cout<<"VTalbe_Addr:"<<(int**)(int*)(&b)<<endl;
        FUNC pf = NULL;
        pf = (FUNC)*((int**)*(int*)(&d)+0);
        pf();
        pf = (FUNC)*((int**)*(int*)(&d)+1);
        pf();
        pf = (FUNC)*((int**)*(int*)(&d)+2);
        pf();
    
        pf = (FUNC)*((int**)*(int*)(&d)+3);
        pf();
    
        Base *pb = & d;
        pf = (FUNC)*((int**)*(int*)(pb)+3);
        pf();
    }

    运行结果:

     

    虚函数表形式

     

     总结:单继承体系中,派生类继承基类,并且有自己独立的虚函数,基类与派生类的虚函数表顺序存放在一张表中,派生类的虚函数表在基类后面,类中的成员变量不影响虚函数表的排布。

     

     

    多继承:

    基类中未完全覆写,派生类中又有虚函数

    #include <iostream>
    
    using namespace std;
    
    class Base1 {
    public:
    virtual void f() { cout << "Base::f" << endl; }
    virtual void g() { cout << "Base::g" << endl; }
    virtual void h() { cout << "Base::h" << endl; }
    };
    
    class Base2 {
    public:
    virtual void f2() { cout << "Base::f2" << endl; }
    virtual void g2() { cout << "Base::g2" << endl; }
    virtual void h2() { cout << "Base::h2" << endl; }
    };
    
    class Derived:public Base1,public Base2
    {
    public:
         void f() { cout << "Derived::f" << endl; } //override
         virtual void i() { cout << "Derived::i" << endl; }
    };
    
    
    typedef void(*FUNC)();
    int main()
    {
        Derived d;
       cout<<sizeof(d)<<endl; Base1
    * p1d = &d; Base2 * p2d = &d; cout<<"p1d:"<<p1d<<endl; cout<<"p2d:"<<p2d<<endl; FUNC pf = NULL; pf = (FUNC)*((int**)*(int*)(p1d)+0); pf(); pf = (FUNC)*((int**)*(int*)(p1d)+1); pf(); pf = (FUNC)*((int**)*(int*)(p1d)+2); pf(); pf = (FUNC)*((int**)*(int*)(p1d)+3); pf();
       cout
    <<"-------------------------"<<endl; pf = (FUNC)*((int**)*(int*)(p2d)+0); pf(); pf = (FUNC)*((int**)*(int*)(p2d)+1); pf(); pf = (FUNC)*((int**)*(int*)(p2d)+2); pf(); // pf = (FUNC)*((int**)*(int*)(p2d)+3); //crash// pf(); }

     

    运行结果

    继承关系:

     虚函数表:

     

     结论:多继承中,每个基类都有自己的虚函数表,他们是独立存放的,如果派生类中有虚函数,那么虚函数表将与第一个继承的基类虚函数表顺序存放(合并)。

     

     

  • 相关阅读:
    【转载】动态加载wpf控件主题样式资源
    paip.批处理清理java项目冗余jar的方法
    paip.java OutOfMemoryError 解决方法o33
    paip.java win程序迁移linux的最佳实践
    paip.java c# .net php python调用c++ c dll so windows api 总结
    paip.提高效率微信 手机app快速开发平台—微网络撬动大市场
    paip.Log4j配置不起作用的解决
    paip.获取地理位置根据Ip
    paip.java 开发中web server的选择jboss resin tomcat比较..
    paip.提升安全性Des加密 java php python的实现总结
  • 原文地址:https://www.cnblogs.com/wangkeqin/p/12887739.html
Copyright © 2011-2022 走看看