深度探索C++对象模型-第五章

说明:

​ <u>不是很清楚的点</u>,用下划线。

解答,用斜体;

重点,用粗体加粗;

第五章 构造、析构、拷贝 语意学

5.1 纯虚函数

  • 拥有纯虚函数的类,为抽象类,不可能拥有实例(不可能创造出一个对象)。

    但若抽象类中有数据成员,则需要一个显式的构造函数去初始化它。

  • 不要把析构函数声明为 pure(纯)。

  • 不要给一个虚函数后面加 const。

5.2 “无继承”情况下的对象构造

当一个class导入一个虚函数时,会发生下列事情:

  1. 每一个class object多负担一个vptr;
  2. 自己定义的构造函数被附加了一些代码,实现vptr的初始化;
  3. 合成拷贝构造函数、赋值构造函数,因为vptr不能用默认的bitwise方式复制了;

5.3 继承体系下的对象构造

在继承下,编译器会扩充每一个constructor,扩充程度视继承体系而定。

constructor的调用伴随了哪些步骤?

  • 初始化列表(member initialization list)的data members初始化操作会被放进constructor的函数本身,并以members的声明顺序为顺序。(如*this->x = 0;)

  • 如果有一个member并没有在初始化列表中,但它在一个default constructor,那么该default constructor 必须被调用(手动)。

  • 在那之前,如果class object有virtual table pointer(s),它(们)必须被设定初始值,指定适当的virtual table(s)

  • 在那之前,所有上一层的base class constructors 必须被调用,以base class 的声明顺序为顺序(与初始化列表的顺序没有关联)。

    1. 如果base class 被列于初始化列表中,那么任何明确指定参数都应该传递过去。

    2. 如果base class 没有列于初始化列表,那么调用default constructor。

    3. 如果base class 是多重继承下的第二或后面的base class ,那么this指针必须有所调整。

  • <u>在那之前,所有 virtual base class constructors 必须被调用,从左到右,从最深到最浅。</u>

    1. 如果class 被列于初始化列表中,那么如果有任何明确指定的参数,都应该传递过去,若没有列于初始化列表中,则调用default constructor。
    2. 此外,class中的每一个virtual base class subobject的偏移量必须在执行期可存取。
    3. 如果class object 是最底层的class,某constructors可能被调用;某些用以支持这个行为的机制必须被放进来。

【注】在那之前,是指在用户代码执行前。

其中的虚拟继承

为了防止重复对virtual base class调用构造函数,规定:只有在继承体系最深层的object才可以对virtual父类进行调用构造初始化。

其中的vptr语意学

vptr在constructor何时被初始化?

base class constructors调用操作之后,但是在程序员供应的码或是初始化列表中所列的members初始化操作之前。

5.4 对象复制语意学

在复制操作时,需要一个面对自我拷贝的过滤过程:

if( this == &rhs) return *this;

当设计一个class,并以一个class object 指定另一个class object时,有三种选择:

  1. 什么都不做,实施默认行为。

  2. 提供一个explicit copy assignment operator。

  3. 明确拒绝一个class object指定给另一个class object。

一个class对于默认的copy assignment operator,在以下情况下不会表现出 bitwise copy语意:

  1. 当一个class的 base class 有一个copy assignment operator时,

  2. 当一个class 的 member object,而其 class 有一个 copy assignment operator 时,

  3. 当一个class 声明了任何 virtual functions 时,

  4. 当class继承一个 virtual base class 时。但尽可能不要允许一个virtual base class的拷贝操作,也尽量不要在其中声明数据。

构造这样的一个继承体系:

class Base {
    public: virtual ~Base() {}
    virtual void show() { cout << "Base" << endl; }
};

class Derived : public Base {
    public: void show() { cout << "Derived" << endl; }
};

子类Derived类重写了基类Base中的show方法。 编写下面的测试代码:

Base b; 
Derived d;

b.show(); 
d.show();

结果是:

Base

Derived

Base的对象调用了Base的方法,而Derived的对象调用了Derived的方法。因为直接用对象来调用成员函数时不会开启多态机制,故编译器直接根据b和d各自的类型就可以确定调用哪个show函数了,也就是在这两句调用中,编译器为它们每一个都确定了一个唯一的入口地址。这实际上类似于一个重载多态,虽然这两个show函数拥有不同的作用域。 那这样呢: Base b; Derived d; b.show(); b = d; b.show(); 现在,一个Base的对象被赋值为子类Derived的对象。

那这样呢:

Base b; 
Derived d;

b.show(); 
b = d; 
b.show();

现在,一个Base的对象被赋值为子类Derived的对象。

结果是:

Base

Base

对于熟悉Java的人而言,这不可理解。但实际上,C++不是Java,它更像C。“b = d”的意思,并不是Java中的“让一个指向Base类的引用指向它的子类对象”,而是“把Base类的子类对象中的Base子对象分割出来,赋值给b”。所以,只要b的类型始终是Base,那么b.show()调用的永远都是Base类中的show函数;换句话说,编译器总是把Base中的那个show函数的入口地址作为b.show()的入口地址。这根本就没用上多态。

单继承下的重写多态

那我们再这样:

Base b; 
Derived d;
Base *p = &b;

p->show();
p = &d;
p->show();

这时,结果就对了:

Base

Derived

p是一个指向基类对象的指针,第一次它指向一个Base对象,p->show()调用了Base类的show函数;而第二次它指向了一个Derived对象,p->show()调用了Derived类的show函数。

总结:也就是说,只有是指针或者引用才是真正的多态,将子对象赋给父类对象其实类型向上转型

个人觉得C++容易弄混淆的地方(持续更新):

1.const和指针的修饰问题

const char * a; //一个指针a指向const char

char const *a; //这两个是a指向的内容是常量,不能改变

char * const a; //首先a 是指针然后还是const

const (char*) a; //这两个是a指针本身是常量,指针本身不能改变

其实,可以看出如果const修饰的char(也就是类型本身或者是 *variable对指针的解引用)就是指针指向的内容是常量,反之就是修饰指针本身的。那我们可以总结一个识别方法就是:看const 两边(当然有的只有一边)的类型是类型(指针指向的内容)就是类型变量本身是常量(如const char * a和char const a 的const两边是char,a)。

当然两者都是常量就是:const char * const a;第一个const是类型常量,第二个才是指针常量。同样给出 const char &a ;const char *a;在传递参数时使用。

2.数组和指针的组合问题

char * a[M]; 这是指针数组,就是每一个元素是指针的数组,每个元素都要初始化。a[M]一看就是数组,这个数组每一个元素是char *,所以可以将char *扩展为一维数组然后a[M]就是二维数组了。其实就是M个指针。

char (a)[N]; 这是一个指针,这个指针指向N个char元素,即指向数组的指针,其实就是一个指针。把(a)看着一个变量,这个变量是指向N个元素的指针,所以只是一个一维数组。把char (*a)[N]看成是char b[N]就可以了。

3.C++变量的初始化

对于内置类型局部变量不进行初始化,但是分配地址,全局变量会进行默认初始化。对于类类型局部变量(没有显式初始化)会进行默认初始化(有默认构造函数,否则报错),但其内部的内置数据成员不会进行初始化(如果在默认构造函数没有进行初始化)。数组也是同样。

参考文章

《深度探索C++对象模型(Inside The C++ Object Model )》学习笔记:https://dsqiu.iteye.com/blog/1669614

c++,为什么要引入虚拟继承 :https://www.cnblogs.com/mylinux/p/4725833.html

RTTI、虚函数和虚基类的实现方式、开销分析及使用指导:http://baiy.cn/doc/cpp/inside_rtti.htm

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

推荐阅读更多精彩内容

  • 从前我很鄙视微商, 现在,我自己就是一名微商。 自从淘宝解决了万千人民的就业问题之后,微信的发展也逐渐催生出了一个...
    一只大瑞阅读 1,912评论 0 0
  • Everyone may encounter all kinds of intersections, someti...
    大林dalin阅读 525评论 0 50
  • 核心内容部分 一、具有以下特质有助于提高成功的心理预期1、认同努力与结果的协变。2、相信对于结果的控制源自于自身,...
    昆明家庭教育联盟阅读 889评论 0 1
  • 今天是星期日,我和妈妈打扫卫生,我们先扫地,后有又拖地。我自己收拾了我的学习桌,又把我们晒干的收拾衣服收拾起来。屋...
    董子璐阅读 208评论 0 0
  • test2 test2 API列表 API名称 认证方式 描述 getUserInfo APP ge...
    tommyhxh阅读 1,488评论 0 0