• [C++对象模型][7]单继承与虚函数表


    一 单继承

    1) 代码:

    Code
    #include <iostream>
    using namespace std;

    class A
    {
    public:
        
    void f1(){cout << "A::f1" << endl;}
        
    void f2(){cout << "A::f2" << endl;}
        
    virtual void v1(){cout << "A::v1" << endl;}
        
    virtual void v2(){cout << "A::v2" << endl;}
        
    int x;
    };

    class B : public A
    {
    public:
        
    void f2(){cout << "B::f2" << endl;} // 覆盖
        void v2(){cout << "B::v2" << endl;} // 重写

        
    void f3(){cout << "B::f3" << endl;} 
        
    virtual void v3(){cout << "B::v3" << endl;}
        
    int y;
    };

    class C : public B
    {
    public:
        
    void f3(){cout << "C::f3" << endl;} // 覆盖
        void v1(){cout << "C::v1" << endl;} // 重写
        void v3(){cout << "C::v3" << endl;} // 重写
        int z;
    };

    2)类图:

    3)VS2008的编译选项查看布局:

    4)可视化表示:

    5)代码验证:

    Code
    typedef void (*Fun)();

    void PrintVTable(A *pA)
    {
        
    int *pVT = (int*)*(int*)(pA);
        Fun
    * pF = (Fun*)(pVT + 0);
        
    int iLength = 0;
        
    while(*pF != NULL)
        {
            (
    *pF)();
            
    ++iLength;
            pF 
    = (Fun*)(pVT + iLength);
        }
    }
    void PrintMembers(A *pA)
    {
        
    int *= (int*)(pA);
        
    int i = 1;
        
    while(i <= 3)
        {
            cout 
    << *(p+i) << endl;
            i
    ++;
        }
    }
    void TestVT()
    {
        A 
    *pA = new C();
        C 
    *pC = dynamic_cast<C*>(pA);
        pC
    ->= 10;
        pC
    ->= 20;
        pC
    ->= 30;
        PrintVTable(pA);
        PrintMembers(pA);
        delete pA;
    }

    6)验证代码运行结果:

    7)总结:

    单继承的对象的布局,第一个为虚函数表指针vtbl,其后为成员且先基类后子类,虚函数表里包含了所有的虚函数的地址,以NULL结束。虚函数如果子类有重写,就由子类的重新的代替。

    二 单继承运行时类型转化

    1)代码验证:

    Code
    void TestDynamicCast()
    {
        A 
    *pA = new C();
        cout 
    << "A:" << pA << endl;
        B 
    *pB = dynamic_cast<B*>(pA);
        cout 
    << "B:" << pB << endl;
        C 
    *pC = dynamic_cast<C*>(pA);
        cout 
    << "C:" << pC << endl;
    }

    2)验证代码运行结果:

    3)总结:

    我们上面看了单继承的内存布局,而这样的内存布局也就决定了当dynamic_cast的时候,都还是同一地址,不需要做指针的移动。只是类型的改变即所能访问的范围的改变。

    三 完!


    作者:iTech
    微信公众号: cicdops
    出处:http://itech.cnblogs.com/
    github:https://github.com/cicdops/cicdops

  • 相关阅读:
    [Swift]数学库函数math.h | math.h -- mathematical library function
    [Swift]LeetCode492. 构造矩形 | Construct the Rectangle
    FansMail:邮件发送标准API与技术实现(Java)
    FansMail:邮件发送标准API与技术实现(Java)
    大话世界格局:春秋五霸与战国七雄
    大话世界格局:春秋五霸与战国七雄
    大家好,我是FansUnion,雷文
    大家好,我是FansUnion,雷文
    2013年总结(2)-财务收入与支出
    2013年总结(2)-财务收入与支出
  • 原文地址:https://www.cnblogs.com/itech/p/1398224.html
Copyright © 2020-2023  润新知