C++ 对象的内存布局(上) - 陈皓专栏 【空谷幽兰,心如皓月】 - CSDN博客

来源:百度文库 编辑:神马文学网 时间:2024/04/27 13:52:25
07年12月,我写了一篇《C++虚函数表解析》的文章,引起了大家的兴趣。有很多朋友对我的文章留了言,有鼓励我的,有批评我的,还有很多问问题的。我在这里一并对大家的留言表示感谢。这也是我为什么再写一篇续言的原因。因为,在上一篇文章中,我用了的示例都是非常简单的,主要是为了说明一些机理上的问题,也是为了图一些表达上方便和简单。不想,这篇文章成为了打开C++对象模型内存布局的一个引子,引发了大家对C++对象的更深层次的讨论。当然,我之前的文章还有很多方面没有涉及,从我个人感觉下来,在谈论虚函数表里,至少有以下这些内容没有涉及: 1)有成员变量的情况。2)有重复继承的情况。3)有虚拟继承的情况。4)有钻石型虚拟继承的情况。 这些都是我本篇文章需要向大家说明的东西。所以,这篇文章将会是《C++虚函数表解析》的一个续篇,也是一篇高级进阶的文章。我希望大家在读这篇文章之前对C++有一定的基础和了解,并能先读我的上一篇文章。因为这篇文章的深度可能会比较深,而且会比较杂乱,我希望你在读本篇文章时不会有大脑思维紊乱导致大脑死机的情况。;-) 对象的影响因素
 简而言之,我们一个类可能会有如下的影响因素: 1)成员变量2)虚函数(产生虚函数表)3)单一继承(只继承于一个类)4)多重继承(继承多个类)5)重复继承(继承的多个父类中其父类有相同的超类)6)虚拟继承(使用virtual方式继承,为了保证继承后父类的内存布局只会存在一份)上述的东西通常是C++这门语言在语义方面对对象内部的影响因素,当然,还会有编译器的影响(比如优化),还有字节对齐的影响。在这里我们都不讨论,我们只讨论C++语言上的影响。 本篇文章着重讨论下述几个情况下的C++对象的内存布局情况。 1)单一的一般继承(带成员变量、虚函数、虚函数覆盖)2)单一的虚拟继承(带成员变量、虚函数、虚函数覆盖)3)多重继承(带成员变量、虚函数、虚函数覆盖)4)重复多重继承(带成员变量、虚函数、虚函数覆盖)5)钻石型的虚拟多重继承(带成员变量、虚函数、虚函数覆盖) 我们的目标就是,让事情越来越复杂。 知识复习
 我们简单地复习一下,我们可以通过对象的地址来取得虚函数表的地址,如:           typedef void(*Fun)(void);             Base b;             Fun pFun = NULL;             cout << "虚函数表地址:" << (int*)(&b) << endl;            cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;             // Invoke the first virtual function              pFun = (Fun)*((int*)*(int*)(&b));            pFun(); 我们同样可以用这种方式来取得整个对象实例的内存布局。因为这些东西在内存中都是连续分布的,我们只需要使用适当的地址偏移量,我们就可以获得整个内存对象的布局。 本篇文章中的例程或内存布局主要使用如下编译器和系统:1)Windows XP 和 VC++ 20032)Cygwin 和 G++ 3.4.4 单一的一般继承
 下面,我们假设有如下所示的一个继承关系:  
 请注意,在这个继承关系中,父类,子类,孙子类都有自己的一个成员变量。而了类覆盖了父类的f()方法,孙子类覆盖了子类的g_child()及其超类的f()。 我们的源程序如下所示: class Parent {public:    int iparent;    Parent ():iparent (10) {}    virtual void f() { cout << " Parent::f()" << endl; }    virtual void g() { cout << " Parent::g()" << endl; }    virtual void h() { cout << " Parent::h()" << endl; } }; class Child : public Parent {public:    int ichild;    Child():ichild(100) {}    virtual void f() { cout << "Child::f()" << endl; }    virtual void g_child() { cout << "Child::g_child()" << endl; }    virtual void h_child() { cout << "Child::h_child()" << endl; }}; class GrandChild : public Child{public:    int igrandchild;    GrandChild():igrandchild(1000) {}    virtual void f() { cout << "GrandChild::f()" << endl; }    virtual void g_child() { cout << "GrandChild::g_child()" << endl; }    virtual void h_grandchild() { cout << "GrandChild::h_grandchild()" << endl; }};我们使用以下程序作为测试程序:(下面程序中,我使用了一个int** pVtab 来作为遍历对象内存布局的指针,这样,我就可以方便地像使用数组一样来遍历所有的成员包括其虚函数表了,在后面的程序中,我也是用这样的方法的,请不必感到奇怪,)     typedef void(*Fun)(void);     GrandChild gc;          int** pVtab = (int**)&gc;     cout << "[0] GrandChild::_vptr->" << endl;    for (int i=0; (Fun)pVtab[0][i]!=NULL; i++){                pFun = (Fun)pVtab[0][i];                cout << "    ["<" << endl;                pFun = (Fun)pVtab[0][0];                cout << "     [0] ";                pFun();                 pFun = (Fun)pVtab[0][1];                cout << "     [1] ";pFun();                 pFun = (Fun)pVtab[0][2];                cout << "     [2] ";pFun();                 pFun = (Fun)pVtab[0][3];                cout << "     [3] "; pFun();                 pFun = (Fun)pVtab[0][4];                cout << "     [4] "; cout<"<"< C++ 对象的内存布局(上) - 陈皓专栏 【空谷幽兰,心如皓月】 - CSDN博客 我是怎么招聘程序员的 - 陈皓专栏 【空谷幽兰,心如皓月】 - CSDN博客 五种应该避免的代码注释 - 陈皓专栏 【空谷幽兰,心如皓月】 - CSDN博客 Unix传奇 (上篇) - 陈皓专栏 【空谷幽兰,心如皓月】 - CSDN博客 谈谈职业规划——陈皓的采访 - 陈皓专栏 【空谷幽兰,心如皓月】 - CSDNBl... C#的内存管理知识 - dz_huanbao的专栏 - CSDN博客 图解高端内存[zz] - zhengaw的专栏 - CSDN博客 C语言宏的学习: - henry19850318的专栏 - CSDN博客 C语言宏的学习: - henry19850318的专栏 - CSDN博客 异常处理 - [C++] - guomei的专栏 - CSDN博客 C Recommend Book List - ehui928的专栏 - CSDN博客 C语言字符串函数大全 - amossavez的专栏 - CSDN博客 javacard mask.c 文件结构 - tccth4091的专栏 - CSDN博客 C 内存对象大会战 内存对齐的规则以及作用 - one_snail的专栏 - CSDN博客 一种检查内存泄漏的方法 - QQ471007827的专栏 - CSDN博客 OOP面向对象编程——C++ - winnie的专栏 - CSDN博客 面向对象分析过程案例实战 - FcBayernMunchen的专栏 - CSDN博客 在Visual C++中检测和隔离内存泄漏 - WuOu的专栏 - CSDN博客 c++五种内存分配、堆与栈区别 - mfreesky的专栏 - CSDN博客 Resharper上手指南(转自博客园的恋上Csharp) - 唐太宗的专栏 - CSDN... 探讨C 中对象的“浅拷贝”与“深拷贝” - Chris_Magic的学习笔记 - CSDN博客 baozhengw的专栏 - CSDN博客 C-Free4.1专业版注册码破解 - xiufeng_wang的专栏 - CSDN博客