深度探索c++对象模型

深度探索C++对象模型》中文电子版概述 C++中,我们通过关键字class定义一个类,然后可以创建该类型的实例,也就是对象。例如:public:return 0;在这个例子中,Person类定义了一个成员函数sayHello,然后我们创建了一个Person类型的对象person,并通过它调用sayHello函数。异常安全通常分为三个等级:基本保证、强保证和不抛出保证。基本保证要求在异常发生时,对象处于有效状态但可能与操作前不同。强保证要求如果操作失败,对象应保持操作前的状态不变。 阅读详情

所谓知己知彼,百战不殆。只有深入了解了c++对象的内存布局,我们才能更熟练运用c++这门语言。
运行环境vs2013

一单继承和多继承的结合

class C
{
public:
    C() :c(1){}
private:
    int c;
};
class B1 :public C
{
public:
    B1() :C(), b1(2){}
private:
    int b1;
};
class B2 :public C
{
public:
    B2() :C(), b2(3){}
private:
    int b2;
};
class A :public B1, public B2
{
public:
    A() :B1(), B2(), a(4){}
private:
    int a;
};
int main()
{
    A f1;
    cout<<sizeof(f1);
    return 0;
}

因为不是virtual继承,继承关系如下:

这里写图片描述
我们转到内存去看一下对象空间是怎么分布的:

0x00CAF800  01 00 00 00  ....//B1中的c的成员数据
0x00CAF804  02 00 00 00  ....//B1特有的的成员数据
0x00CAF808  01 00 00 00  ....//B2的c的成员数据
0x00CAF80C  03 00 00 00  ....//B2特有的成员数据
0x00CAF810  04 00 00 00  ....//A特有的成员数据
0x00CAF814  cc cc cc cc  ????

所以最后的数据分布是这样的:
这里写图片描述

所以根据对象模型,大家应该知道输出的值是多少了吧。

二.菱形继承

class C
{
public:
    C() :c(1){}
private:
    int c;
};
class B1 :virtual public C
{
public:
    B1() :C(), b1(2){}
private:
    int b1;
};
class B2 :virtual public C
{
public:
    B2() :C(), b2(3){}
private:
    int b2;
};
class A :public B1, public B2
{
public:
    A() :B1(), B2(), a(4){}
private:
    int a;
};
int main()
{
    A aa;
    B1 bb1;
    B2 bb2;
    C cc;
    cout << sizeof(aa);//24
    cout << sizeof(bb1);//12
    cout << sizeof(bb2);//12
    cout << sizeof(cc);//4
    return 0;
}

正如其名字,继承关系如下:
这里写图片描述
首先我们还是转到内存去看看对象空间如何分布的
取类A的对象的地址,得到:

0x0114FC84  70 dd 83 00  //????
0x0114FC88  02 00 00 00  //B1中特有的数据
0x0114FC8C  ac db 83 00  //????
0x0114FC90  03 00 00 00  //B2中特有的数据
0x0114FC94  04 00 00 00  //A中特有的数据
0x0114FC98  01 00 00 00  //C中特有的数据

仅仅根据这一段内存地址,显然,我们不知道0x0114FC84,0x0114FC8C中的类似地址的数据有何作用。既然如此我们就到该地址上一探究竟:

0x0083DD70  00 00 00 00  ....
0x0083DD74  14 00 00 00  ....//20
0x0083DBAC  00 00 00 00  ....
0x0083DBB0  0c 00 00 00  ....//12

联系上面,我们可以得知,改地址指向的内容就是B1和B2类到类A数据的偏移量。
最后我们可以得出数据分布:
这里写图片描述

三.有虚函数的virtual继承

class B1
{
public:
    B1() :b1(1){}
    virtual void fun1(){}
    virtual void fun2(){}
private:
    int b1;
};

class B2
{
public:
    B2() :b2(2){}
    virtual void fun3(){}
    virtual void fun4(){}
private:
    int b2;
};

class A :public B1, public B2
{
public:
    A() :B1(), B2(), a(3){}
    void fun1(){};
    void fun2(){};
    void fun3(){};
    virtual void fun5(){};
private:
    int a;
};

int main()
{
    A f1;
    cout<<sizeof(f1);//20
    return 0;
}

关于虚表,可以参见我的上一篇博客。
由代码可知,继承关系如下:
这里写图片描述
在这里大家不妨猜测一下对象空间内是怎样的

转到内存:

0x00FBFDDC  90 cc 0f 00  ??..//虚表地址
0x00FBFDE0  01 00 00 00  ....//类B1的成员变量b1
0x00FBFDE4  a4 cc 0f 00  ??..//虚表地址
0x00FBFDE8  02 00 00 00  ....//类B2的成员变量b2
0x00FBFDEC  03 00 00 00  ....//类A的成员变量a

那么第一个虚表指针指向的虚表中到底有哪几个函数,第二个虚表中是哪几个函数呢?
下面一起进入虚表看看:
第一个虚表

0x000FCC90  07 13 0f 00  ....//A::fun1()
0x000FCC94  de 13 0f 00  ?...//A::fun2()
0x000FCC98  45 11 0f 00  E...//A::fun5()
0x000FCC9C  00 00 00 00  ....

通过运行这三个函数可知分别为A::fun1(),A::fun2(),A::fun5()

第二个虚表

0x000FCCA4  ff 10 0f 00  ....//A::fun3()
0x000FCCA8  ca 13 0f 00  ?...//B2::fun4()
0x000FCCAC  00 00 00 00  ....

通过运行这三个函数可知分别为A::fun13(),B::fun4()

因此我们可以得出一个结论:在此类继承中,对象空间会维护两张虚表,并且派生类中新增的虚函数会放在第一张虚表中。
最后我们可以得出数据分布:
这里写图片描述

四.有虚函数的菱形继承

class C
{
public:
    virtual void fun(){}
private:
    int c;
};
class B1 :virtual public C
{
public:
    virtual void fun(){}
    virtual void fun1(){}
private:
    int b1;
};
class B2 :virtual public C
{
public:
    virtual void fun(){}
    virtual void fun2(){}
private:
    int b2;
};
class A :public B1, public B2
{
public:
    void fun(){}
private:
    int a;
};
typedef void(*fun)();
void funtest(A&b)
{
    int i = 0;
    int*p = (int*)*((int*)(&b)+3);
    while (*p)
    {
        fun fn = (fun)*p;
        fn();
        p++;
    }
}
int main()
{
    C f1;
    B1 f2;
    B2 f3;
    A f4;
    cout << sizeof(f1);//8
    cout << sizeof(f2);//20
    cout << sizeof(f3);//20
    cout << sizeof(f4);//36
    return 0;
}

继承关系如下
这里写图片描述
由于C对象的结构比较复杂,先从B1开始分析

1.B1
首先注意这里并没有构造函数,如果有了构造函数,结构就要变化了。
通过监视窗口给c,b1赋值为1,2
打开内存:

0x005FFCA8  7c cc 1e 01  |?..//????
0x005FFCAC  90 cc 1e 01  ??..//????
0x005FFCB0  02 00 00 00  ....//类B1数据b1
0x005FFCB4  88 cc 1e 01  ??..//????
0x005FFCB8  01 00 00 00  ....//类C数据c

我们不知道内存中的这三个地址代表什么,只能到该地址上去查看
(1)0x005FFCA8 7c cc 1e 01

0x011ECC7C  64 10 1e 01  d...
0x011ECC80  00 00 00 00  ....

显然这是一张虚表,该函数是B1中新增的函数fun1()
(2)0x005FFCAC 90 cc 1e 01

0x011ECC90  fc ff ff ff  ?...
0x011ECC94  08 00 00 00  ....

这是一个偏移量,表示到基类数据的偏移
(3)0x005FFCB4 88 cc 1e 01

0x011ECC88  28 10 1e 01  (...
0x011ECC8C  00 00 00 00  ....

是一张虚表,该函数是B1中重写的fun( )

由此可得B1的对象数据分布:
这里写图片描述

注意:如果B1中没有新增函数,那么B1对象只维护一张虚表;
如果B1中有新增函数,那么B1对象维护两张虚表

2.A

0x002EFDE4  08 dd 2e 01  .?..//类B1虚表指针
0x002EFDE8  28 dd 2e 01  (?..//到基类数据的偏移
0x002EFDEC  02 00 00 00  ....//类B1特有数据

0x002EFDF0  14 dd 2e 01  .?..//类B2虚表指针
0x002EFDF4  34 dd 2e 01  4?..//到基类数据的偏移
0x002EFDF8  03 00 00 00  ....//类B2特有数据

0x002EFDFC  04 00 00 00  ....//类B2特有数据

0x002EFE00  20 dd 2e 01   ?..//类C虚表指针
0x002EFE04  01 00 00 00  ....//类C特有数据

(1)0x002EFDE4 08 dd 2e 01

0x012EDD08  69 10 2e 01  i...
0x012EDD0C  00 00 00 00  ....

通过运行这个虚表上的这个函数可知该函数为B1::fun1()
(2)0x002EFDF0 14 dd 2e 01

0x012EDD14  32 10 2e 01  2...
0x012EDD18  00 00 00 00  

通过运行这个虚表上的这个函数可知该函数为B2::fun2()
(3)0x002EFE00 20 dd 2e 01

0x012EDD20  64 10 2e 01  d...
0x012EDD24  00 00 00 00  ....

通过运行这个虚表上的这个函数可知该函数为 A::fun()

最后可得到类A的对象数据分布
这里写图片描述

此时A的对象维护了三张虚表,但我们并不是很清楚这三张虚表的具体作用,我们可以在类中加入虚函数来测试一下:
类C中加入函数virtual void fun3();
类B1加入函数virtual void fun4();
类B2加入函数virtual void fun5();
类A加入函数virtual void fun6();
此时的继承关系如图
这里写图片描述

调用各虚表中的函数,得到对象模型为
这里写图片描述

由此可知:A的对象一共维护三张虚表。
第一张是B1的虚表,包含了类B1中新增的虚函数,以及类A中新增的虚函数。
第二张是B2的虚表,包含了类B2中新增的虚函数。
第三张是C的虚表,包含类C的虚表,如果类C的派生类对虚表上的函数进行重写,该函数地址变为重写后的地址

深度探索c++对象模型(2012版本) 立即下载

相关推荐

深度探索C++对象模型 超高清pdf

深度探索C++对象模型 超高清

深度探索C++ 对象模型

深度探索C++ 对象模型 第二章 对象 第二章第一节 类对象所占用的空间 成员函数不占用类对象的内存空间一个类对象至少占用1个字节的内存空间成员变量是占用对象的内存空间成员函数 每个类只诞生 一个(跟着类走),而不管你用这个类产生了多少个该类的对象; 第二章第二节 对象结构的发

weixin_42252757的博客 1166

深度探索C++对象模型 PDF中文清晰版

深度探索C++对象模型 PDF(书籍),适合有一定C编程基础的同学进一步学习。

深度探索C++对象模型

深度探索C++对象模型 什么是C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各个支持的底层实现机制. 抽象性与实际性之间找出平衡点, 需要知识, 经验以及许多思考. 导读 这本书是C++第一套编译器cfront的设计者所写. 了解C++对象模型, 有助于在语言本身以及面向对象观念两方面层次提升. explicit(明确出现于C++程序代码). implicit...

angbao4913的博客 448

深度探索C++对象模型之美

从概念来上来讲,每一个没有定义构造函数的类都会由编译器来合成一个默认构造函数,以使得可以定义一个该类的对象,但是默认构造函数是否真的会被合成,将视是否有需要而定。C++ standard 将合成的默认构造函数分为 trivial(不重要) 和 notrivial(重要) 两种,前文所述的四种情况对应于notrivial默认构造函数,其它情况都属于trivial。对于一个trivial默认构造函数,编译器的态度是,既然它全无用处,干脆就不合成它。

谢谢大家的关注 3475

深度探索C++对象模型》阅读笔记(完整版)

深度探索C++对象模型》完整阅读笔记

2401_82413779的博客 1887

【亲测免费】 深度挖掘C++奥秘:《深度探索C++对象模型(清晰版)》—— 开启你的专家之路

深度挖掘C++奥秘:《深度探索C++对象模型(清晰版)》—— 开启你的专家之路 【下载地址】深度探索C对象模型清晰版资源下载分享 深度探索C++对象模型(清晰版)资源下载 项目地址: https://gitcode.com/Ope...

gitblog_06646的博客 745

【免费下载】 深度探索C++对象模型 PDF

深度探索C++对象模型 PDF 【下载地址】深度探索C对象模型PDF 深度探索C++对象模型 PDF欢迎来到《深度探索C++对象模型》PDF资源页面 项目地址: https://gitcode.com/open-source-to...

gitblog_09794的博客 777

深度探索C++对象模型》笔记目录

读书笔记,特此记录。 😇😇😇 《深度探索C++对象模型》阅读笔记 第一章 关于对象 《深度探索C++对象模型》阅读笔记 第二章 构造函数语意学 《深度探索C++对象模型》阅读笔记 第三章 Data语意学 《深度探索C++对象模型》阅读笔记 第四章 Function语意学 《深度探索C++对象模型》阅读笔记 第五章 构造、解构、拷贝语意学 《深度探索C++对象模型》阅读笔记 第六章 执行期语意学 《深度探索C++对象模型》阅读笔记 第七章 站在对象模型的尖端...

哇咔咔的博客 359

深度探索C++对象模型.pdf

深度探索C++对象模型.pdf,想深入学习C++的可以看看,侯捷翻译的好书

深度探索cpp对象模型的好博客

http%3A//www.roading.org/archives/

ptgood的博客 193

深度探索C++对象模型》存疑

深度探索C++对象模型》是Standley B.Lippman大师的大作,中文版是侯捷老师翻译的,在译作中侯老师的质量是没得说。三年前对想拜读此书,由于种种原因未能如愿。最近在胡乱看完几本英文书籍之后(英文不好,看着太累)终于决定看几本中文书籍放松一下。        比起英文版的书,看中文版的书真是惬意啊。之前有比较长时间的C++的经验,所以书前几章看着非常轻松,基本上都是已经知道的东西,不过

快乐菜鸟 1569

【免费下载】 深度探索C++对象模型 超高清PDF资源下载

深度探索C++对象模型 超高清PDF资源下载 【下载地址】深度探索C对象模型超高清PDF资源下载 - **文件名**: 深度探索C++对象模型 超高清pdf- **文件格式**: PDF- **文件大小**: [文件大小]- **分辨率**: 超高清 ...

gitblog_06684的博客 1907

深度探索C++对象模型—01关于对象

一本好书:《深度探索C++对象模型》, Stanley B. Lippman 著,侯捷 译 在C语言中,“数据”和“处理数据的操作(函数)”是分开声明的,这种程序方法称为“程序性的”。C++与C在风格上和思考上都有显著的不同,C精瘦简易,C++复杂,很难说明两者孰优孰劣。 加上封装后的布局成本 C++在布局以及存取时间上主要的额外负担是由virtual引起的。包括: virtual fun...

雨纷飞 354
上一篇: 探索友元的继承和传递问题
下一篇: c++知识点大总结
db199410
博客等级 码龄11年 25粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值