对于C++OBP的理解

对于C++OBP的理解

前言:

因为自己查阅文章时经常遇到,这些问题:因为环境不同而导致结果不一致、因为文章跳跃度太大而导致无法理解、因为文章代码运行结果不同而苦恼。

所以为了看我文章的人不会遭遇同样的问题,

以后我的文章将遵循以下原则:

1.会在文章开头标明相关配置与环境

2.尽可能循序渐进(还是看不懂可能是我没有这样的天赋),标出阅读的前提知识

3.列出的代码自己先跑一遍

////////////////////////////////////////

语言:c++

前提知识:

1.类

2.继承

3.静态成员

集成开发环境:Visual Studio 2017

////////////////////////////////////////

文章:

所谓ebo,就是Empty Base Class Optimization,空基类最优化。

空类为没有非静态成员(此处的成员不包含函数)的类,也就是说空类中不包含占空间的成员,因为函数是不会影响类的大小的。

然后稍微解释一下,非静态成员,因为静态成员并不是存储在类对象的空间中,否则对象销毁时静态成员也会被销毁,所以静态成员是不会影响类的大小的。

空类的例子:

class Empty {};

class FuntionOnly

{

public:

void a() {}

int b() { return 1; }

int c(int n) { int m = n; return m; }

};

class StaticMemberOnly{ public:static int a; };

但是说是空类,其实sizeof(空类)=1,这表示其存在(根据其他博客所说,这也与大小的计算方法有关),但是这点空间是毫无意义的,因为它不存储数据,所以就有了ebo,空基类最优化。

空基类最优化:只有空类对象不与同一类型的其他对象或子对象分配在同一地址,就不需要为其分配空间。

可能有人说空类这只有1字节的大小,对程序影响不大,先不说积少成多,c++有一个特性字节对齐,比如说:

class Empty{}

class Test :public Empty

{

int a;

}

sizeof(Test)为多少呢,其为4,但是在没有ebo的情况下呢,其为8,这是因为c++的字节补齐,默认类的大小必须为类中大小最大的成员的倍数。

所以Empty大小为1,int大小为4,一共为5,所以补齐为8(4的倍数),当然你可以选择自定义对齐方式,但这不在这篇文章的讨论范围内。

1的补齐浪费空间是巨大的,当类中其他成员大小越大,补齐的空间就可能越大,这就是ebo的意义所在。

比如说:

class Empty {};

class Empty2:public Empty{};

class Empty3:public Empty2{};

class Empty4:public Empty, public Empty2{};//特殊案例

sizeof(Empty)=1

sizeof(Empty2)=1

sizeof(Empty3)=1

sizeof(Empty4)=1 //这个1的意义不一样,这个也是我写这篇东西的原因

前三个都好理解,他们就是ebo的体现(),那个1的大小只是为了标识类的存在,但是Empty4呢,其实它继承了两次Empty,不符合ebo的规则,父类Empty所以并没有进行最优化,但是实际上Empty4的大小仍为1,我上网查阅了其他博客,但是几乎没有提到这个问题,甚至有出现这个例子,其中还有将其大小写为2的,也许是不同编译器的处理问题,在这里我为跟我一样得到结果为1的同志们解释一下为何为1。

首先,类的继承,继承的原理为何,简单而言,其实就是往类中添加一个隐藏的被继承类的对象,并且编译器将被继承类的中被继承的成员当作继承类的成员,但是ebo只继承中会被使用,被包含时也不会使用。

比如

class Empty {};

class IncludeEmpty

{

public:

int a;

Empty empty;

};

class ExtendEmpty :Empty

{

public:

int a;

};

sizeof(IncludeEmpty)=8

sizeof(ExtendEmpty)=4

那么回来看Empty4,

class Empty4: public Empty,public Empty2{}

Empty4同时继承了Empty和Empty2,而Empty2又继承了Empty,所以实际上Empty4继承了两次Empty,为了查看父类地址,我往类中添加了几个函数(函数是不占类的大小的)

class Empty

{

public:

void pEmpty() { std::cout << "&Empty =" << this << std::endl; }

};

class Empty2 :public Empty

{

public:

void pEmpty2() { std::cout << "&Empty2=" << this << std::endl; }

};

class Empty4 :public Empty2, public Empty

{

public:

void pEmpty4() { std::cout << "&Empty4=" << this << std::endl; }

void pEmpty2_Empty() { std::cout << "Empty2::pEmpty() "; Empty2::pEmpty(); }

void pEmpty() { std::cout << "Empty::pEmpty() "; Empty::pEmpty(); }

};

然后产生对象:empty4

empty4.pEmpty4()        输出:&Empty4=00B9FB00

empty4.pEmpty2()        输出:&Empty2=00B9FB00

empty4.pEmpty2_Empty()  输出:&Empty2::pEmpty() &Empty=00B9FB00

empty4.pempty() 输出:Empty::pEmpty() &Empty=00B9FB01

发现父类Empty2中的Empty与父类Empty的地址不一致,那么将会产生1的大小(sizeof的结果其实是尾地址-首地址),其实这里已经没有在使用ebo,那1的大小是为了区分两个不同的Empty而存在的和前面的三个例子不同,

如果将Empty4改成如下就一目了然了:

class Empty4 :public Empty2, public Empty

{

public:

    int a;

void pEmpty4() { std::cout << "&Empty4=" << this << std::endl; }

void pEmpty2_Empty() { std::cout << "Empty2::pEmpty() "; Empty2::pEmpty(); }

void pEmpty() { std::cout << "Empty::pEmpty() "; Empty::pEmpty(); }

};

此时sizeof(Empty4)=8

很明显,空间超出了4而因为补齐而变为8。这就验证了ebo的准则:只有空类对象不与同一类型的其他对象或子对象分配在同一地址,就不需要为其分配空间。

接下来再谈谈同一地址的问题,即使是同一类型的对象只有分配地址不同,也不需要为其分配空间

再来两个类:

class Integer

{

public:

int a;

}

class Empty5:public Empty,public Integer,public Empty2{}

那么sizeof(Empty5)等于?

其实sizeof(Empty5)=4,仅仅只有Integer类的大小,也就是使用了ebo,因为Empty与Empty2中Empty分配的地址不同。这里Integer必须继承,而且位置必须在Empty与Empty2之间,只有这样才会影响它们的地址,

因为对象的初始化是从父对象开始的,而且初始化顺序与继承顺序一致。

结尾:

那么这篇文章的探讨到此为止,这是本人第一篇文章,只是一时兴起还请大家多多包含,指出错误。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 近日,冯小刚和王思聪共同演绎的《拯救林丹》世纪大片正在热映,全国数百万名观众不惜顶着双十一的经济压力,纷纷购票入场...
    聪明的壹休阅读 1,164评论 0 12
  • 陶渊明采菊,王羲之慕兰,周敦颐爱莲,杨万里喜荷,杜工部独步寻花,花与草因形致义。 苏东坡写竹,郑板桥画竹,白居易咏...
    文心访艺阅读 414评论 1 1
  • 互联网时代,万物皆可“连接”,关键是要知道信息的“关联度”,所谓的关联度,就是人的“认知度”。 认知是生产力,认知...
    内在视域阅读 409评论 0 1
  • 走进学校,周秦看到许多同学还在用课桌拼凑着自家的铺位,忙碌而有条理。天色没完全暗下来,树上挂着还未点亮的彩灯,周秦...
    橘子系列阅读 296评论 11 7