【深度探索C++对象模型】第五章 构造、析构、拷贝语意学

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

1、 一般而言,class的data member应该被初始化,而且只在constructor中或其它member functions中初始化,其它任何操作都将破坏其封装性质,使其维护和修改更加困难。

2、 可以定义并调用一个pure virtualfunction,但它只能被静态调用,不能经由虚拟机制调用。

3、 class设计者一定得定义pure virtual destructor,因为每一个derived class destructor会被编译器加以扩张,静态调用每一个virtualbase class以及上一层base class的destructor。只要缺乏任何一个base class destructors的定义,就会导致链接失败。

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

​ 在“无继承”情况下,观念上,编译器会为class声明一个trivial default constructor、一个trivial destructor、一个trivial copy constructor,以及一个trivial copy assignment operator。然而,事实上trivial members要不是没被定义就是没被调用。

抽象数据类型

​ 如果要将class中的所有成员都设定为常量初值,那么给予一个explicit initialization list会比较有效率些(比起意义相同的constructor的inline expansion而言)。甚至local scope中也是如此,如下例:

  
  void mumble()
  {
      Point local1={1.0,1.0,1.0};
      Point local2;                    
      
      //相当于一个inline expansion
      //explicit initialization list会稍微快些
      local2._x=1.0;
      local2._y=1.0;
      local2._z=1.0;
  }

​ local1的初始化操作会比local2的有效率些。

​ Explicit initialization list有三项缺点:

  • 只有当class members都是public时,才有效;

  • 只能指定常量,因为它们在编译时期就可以被评估求值;

  • 由于编译器并没有自动施行之,所以初始化行为的失败可能会比较高一些;

为继承做准备

​ 具有多态性质相关的类,将为“继承性质”以及某些操作的动态决议做准备。virtual functions的导入促使每一个class object有用一个virtual table pointer。这个指针给我们提供了virtual接口的弹性,其成本是:每一个object需要额外的一个word空间。除了每一个class object多负担一个vptr之外,virtual function的导入引发编译器对class产生膨胀作用:

  • 我们所定义的constructor被附加一些代码,以便初始化vptr;

  • 合成一个copy constructor和一个copy assignment opertor,而且其操作不再是trivial(但implicit destructor仍是trivial);

继承体系下的对象构造

  一般而言,继承体系下编译器对constructor所做的扩充操作以及次序大约如下:

  1. 记录在member initialization list中的data members初始化操作会被放进constructor的函数本体,并以members的声明顺序为顺序;

  2. 如果一个member并没有出现在member initialization list之中,但它有一个default constructor,那么该default constructor必须被调用;

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

  4. 在那之前,所有上一层的base class constructors必须被调用,以base class的声明顺序为顺序(与member inlitialization list顺序没有关联)

    • 如果base class被列于member initialization list中,那么任何显式指定的参数都应该传递过去;

    • 如果base class没有被列于member initialization list中,而它有default constructor,那么就调用之;

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

  5. 在那之前,所有virtual base class constructors必须被调用,从左至右,从最深至最浅;

    • 如果class被列于member initialization list中,那么如果有任何显式指定的参数,都应该传递过去。如果没有列于list之中,而class有一个default constructor,亦应该调用之;

    • 此外,class中的每一个virtual base class subobject的偏置位置,必须在执行期可被存取;

    • 如果class object是最底层的class,其constructors可能被调用;某些用以支持这一行为的机制必须被放进来。

虚拟继承

考虑下面三种类的派生情况:

  
  class Vertex : virtual public Point{...};
  class Vertex3d : public Point3d,public Vertex{...};
  class PVertex : public Vertex3d{...};

​ Vertex的constructor必须也调用Point的constructor。然而,当Point3d和Vertex同为Vertex3d的subobjects时,他们对Point constructor的调用操作一定不可以发生;取而代之的是,作为一个底层的class,Vertex3d有责任将Point初始化。而更往后(往下)的继承,则由PVertex来赋值完成“被共享之Point subobject”。

​ 因此,编译器在虚拟继承中需要对constructor采用不同与普通继承的扩充。

vptr初始化语意学

​ vptr初始化操作应该如何处理?在base class constructors调用操作后,但是在程序员供应的代码或是“member initialization list中所列的members初始化操作”之前。

​ constructor执行算法过程:

  1. 在derived class constructor中,“所有virtual table classes”及“上一次base class”的constructors会被调用;

  2. 上述完成后,对象的vptr(s)被初始化,指向相关的virtual table(s);

  3. 如果由member initialization list的话,将在constructor体内展开来。这必须在vptr被设定之后才做,以免有一个virtual member function被调用;

  4. 最后,执行程序员所提供的代码。

对象复制语意学

  1. 显式拒绝把一个class object指定给另一个class object的做法:将copy assignment operator声明为private,并且不提供其定义。把它设为private,就不允许任何地点(除了member functions及该class的friends之中)做赋值操作。不提供其函数定义,则一旦某个member function或friend企图影响一份拷贝,程序在链接时就会失败。

  2. 只有在默认行为所导致的语意不安全或者不正确时,才需要设计一个copy assignment operator。

  3. 一个class对于默认的copy assignment operator,在以下情况不会表现出bitwise copy语意(不表现出bitwise copy语意,则编译器生成default copy assignment operator):

    • 当class内含一个members object,而其class有一个copy assignment operator时

    • 当一个class的base class有一个copy assignment operator

    • 当一个class声明了任何virtual functions时

    • 当class继承一个virtual base class时

    对于Point class,这样的赋值操作:

      
      Point a,b;
      ……
      a=b;

    由bitwise copy完成,把Point b拷贝到Point a,期间并没有copy assignment operator被调用。

析构语意学

​ 如果class没有定义destructor,那么只有在其内含的member object或base class拥有destructor时,编译器才会自动合成出一个destructor。一个由程序员定义的destructor被扩展的方式类似constructors被扩展的方式,只是顺序相反:

  1. destructor的函数本体首先被执行;

  2. 如果class拥有member class objects,而后者拥有destructors,那么它们将以声明的相反顺序而调用;

  3. 如果object内含一个vptr,则现在被重新设定以指向适当base class之virtual table;

  4. 如果有任何直接的nonvirtual base classes拥有destructor,它们将以声明的相反顺序而调用;

  5. 如果有任何virtual base classes拥有destructor,而前面讨论的这个class是most-derived class,那么它们会以原先构造顺序的相反顺序被调用。

深度探索C++对象模型》笔记 第一章 1.多态:不同对象去完成同一行为时,可以展现出不同的形态。在运行时,可以通过指向基类的指针或引用,来调用实现派生类中的方法。 作用:在面向对象的程序设计中,使用多态能够增强程序的可扩充性,即类型需要修改或增加功能时,只需改动或增加较少的代码,提高开发效率。 2.C++对象模型 所有的非静态数据成员存储在对象本身中。所有的静态数据成员、成员函数(包括静态与非静态)都置于对象之外。另外,用一张虚函数表(virtual table)存储所有指向虚函数的指针,并在表头附加上一个该类的type_info对象, 阅读详情

相关推荐

深度探索C++对象模型——5_构造拷贝语义学

深度探索C++对象模型

wogan101的博客 284

深度探索c++对象模型》第二章笔记

有四种情况,会导致“编译器必须为未声明constructor 之 classes合成--个default constructor”.C++ Stardand 把那些合成物称为implicit nontrivial defaultconstructors。

StudyWinter的博客 1752

c++ 类的 构造函数,explicit,初始化列表看这一篇就够了

c++ 类的 构造函数,explicit,初始化列表看这一篇就够了构造函数多个构造函数函数默认参数隐式转换和explicit构造函数初始化列表 构造函数 构造函数:在类中有一种特殊的成员函数,他的名字和类名相同,这个特殊的成员函数会被系统自动调用,这个成员函数叫做构造函数。因为构造函数会被系统自动调用,所以我们可以理解成构造函数的目的就是初始化类对象的数据成员。 构造函数没有返回值。构造函数的特殊之处。 不可以手动调用构造函数,否则编译出错。 正常情况下,构造函数应该被声明为public。因为我们创建一个

u014339447的博客 1285

C++面对对象(下)

讲解大致内容为初始化列表,explicit关键字,static(静态)成员

qq_45591898的博客 1331

C++】类与对象(四)——初始化列表|explicit关键字|static成员|友元|匿名对象

初始化列表,explicit关键字,static成员,友元,匿名对象。

weixin_73551991的博客 1284

深度探索C++对象模型第五章构造拷贝语意学收货

1.不要把函数声明为纯虚函数 因为如果这个类被继承了,那么子类在时,是会调用父类的函数的,而如果纯虚函数被调用,就会终止程序(这个不同编译器不一样) 2.指针取地址上的内容和指针指向对应地址的区别 在看书过程中看到这样一段代码: 本来我以为delete是有问题的,因为我理解成了这样: heap=&local 但是这两者是有区别的。书上那样的写法,其实是使...

qq_34489443的博客 253

深度探索C++对象模型》读书笔记第五章构造拷贝语意学

深度探索C++对象模型》读书笔记第五章:构造拷贝语意学 对于abstract base class(抽象基类),class中的data member应该被初始化,并且只在constructor中或者在其他member functions中指定初值。 纯虚函数的存在 纯虚函数,虚函数在声明后加上 = 0,纯虚函数的意义在于只定义一个可继承的接口,并没有实现(虚函数意义在于定义一个可继...

yhcuac 1022

C++-----深度探索C++对象模型-第五章-构造拷贝语意学(二)

1、虽然一个类的函数是虚函数,但是其调用操作员静态的决议出来的。 2、构造函数的函数本体必须条件式的测试传进来的参数,然后决定调用或不调用相关的虚基类构造函数。由最底层的派生类进行虚基类的构造函数的调用,这种机制会压制中间层级类中构造函数对虚基类构造函数的调用。(菱形继承,最底层的派生类会调用最上层虚基类的构造函数,而在调用中间两个基类构造时,将参数设置为flase,这样中间两个基类的构造函...

一个人的学习和碎碎念 329

C++-----深度探索C++对象模型-第五章-构造拷贝语意学(一)

1、拥有纯虚函数的基类不可能有实例对象。 2、一般来说,类的数据成员应该被初始化,并且只在构造函数中或类的其他成员函数中指定初值,其他操作都将破坏封装特性。 3、C++中,纯虚函数是可以定义和调用的,但是只能被静态的调用,不能经过虚拟机制来调用。 4、不要将虚函数定义为纯虚函数,定义为虚函数比较好。因为在每一个派生类的函数都会被编译器加以扩张,以静态调用的方式调用其每一个虚基类以及上...

一个人的学习和碎碎念 280

深度探索C++对象模型复习和学习 第五章构造拷贝语意学

待续

学峰的学习笔记 436

[读书笔记]《深度探索C++对象模型

文章目录前言第一章 关于对象第二章 构造函数语意学构造函数拷贝构造函数初始化列表第三章 Data 语意学第四章 Function 语意学非静态成员函数静态成员函数虚成员函数第五章 构造拷贝语意学RTTI模板函数的实现逻辑 前言 俗话说得好,好记性不如烂笔头,本文主要是重温了一下经典书籍《深度探索C++对象模型》,然后一些内容摘录,主要记录的是我自己的精简版,建议读者有相关的知识需要还是慢慢去啃一下原书比较好。 第一章 关于对象 首先介绍了 C++ 类的情况, C++类的内存存储方式是:只包含非静态成

Chris_zhangrx的博客 1475

深度探索C++对象模型》阅读笔记 第五章 构造、解拷贝语意学

const 成员变量的用法和普通 const 变量的用法相似const 成员函数可以使用类中的所有成员变量,但是不能修改它们的值一旦将对象定义为常对象之后,不管是哪种形式,该对象就只能访问被 const 修饰的成员了(包括 const 成员变量和 const 成员函数),因为非 const 成员可能会修改对象的数据(编译器也会这样假设),C++禁止这样做。1. 即使是一个抽象基类,如果它有非静态数据成员,也应该给它提供一个带参数的构造函数,来初始化它的数据成员。或许你可以通过其派生类来初始化它的数据成员(假

哇咔咔的博客 344

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

构造拷贝语意学 抽象基类仍然需要一个显式的构造函数以初始化成员变量。 纯虚函数的存在 纯虚函数可以被静态调用,不可以通过虚拟机制调用。 但是纯虚函数一定要被定义。因为对于派生类来说,总要调用基类的函数,基类不定义函数会导致连接失败。 一 “无继承”情况下的对象构造 Plain OI’ Data类型:C风格结体类型,无需构造的过程,直接申请内存并复制内...

7now_的博客 374

深度探索C++对象模型》勘误表

深度探索C++对象模型》(侯捷译),英文原版书名为《Inside the C++ Object Model》,Stanley B.Lippman著。光看作者和译者的名字,就知道这本书非同反响。的确,无论是这本书的原版还是译作,都被读者给予了很高的评价。我,作为一名C++的爱好者,当然是怀着一份无比景仰的心情,仔细阅读完了全书。现在将书中我觉得需要勘误的地方摘出来,与大家共享。1.第五章构造

mlite的专栏 2242

[读书笔记]深度探索C++模型_第五章_构造拷贝语意学

5.1“无继承”情况下的对象构造 考虑下面这个程序片段: (1) Point global; (2) (3) Point foobar() (4) { (5) Point local; (6) Point *heap = new Point; (7) *heap = local; (8) // ... stuff ... (9) delete heap; (10) return...

xy_cpp的博客 269

深度探索C++对象模型___小张大肝第五章 11月7号

深度探索C++对象模型___小张大肝第五章 11月7号

weixin_46235863的博客 451

深度探索C++对象模型:5.构造拷贝语意学

第五章构造拷贝语意学 考虑下面这个abstract base class声明: class Abstract_base{ public:     virtual ~Abstract_base() = 0;     virtual void interface() const =0;     virtual const char*         mumble()

walkerkalr的专栏 1397

问答学习《深度探索C++对象模型》系列

经过数次翻看《深度探索C++对象模型》和翻看别人的笔记,还是决定自己动手写一下该本书的笔记。笔记采用问答的方式是因为在UC实习时我的指导老师的影响:你不要为了看书而看书,你要从中学到东西就要带着疑问去学习。于是有了这一系列的笔记,感谢我的指导老师让我明白:生命不息,学习不止。 第一章:《深度探索C++对象模型》读书笔记之关于对象 第二章:《深度探索C++对象模型》读书笔记之构造函数语意学

冰枫的随笔 1323

深度探索C++对象模型》 读书笔记:第五章 构造、解拷贝语意学

class Abstract_base { public: virtual ~Abstract_base() = 0; virtual void interface()const = 0; virtual const char* mumble() const{ return _mumble; } protected: char* _mumble; }; 上面这个类的设计存在一个问题,虽...

junya_zhang的博客 308
上一篇: 【深度探索C++对象模型】第四章 Function语意学
下一篇: 【深度探索C++对象模型】第六章 执行期语意学
stt2019
博客等级 码龄13年 52粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值