首页 > 其他分享 >第五章 构造、析构、拷贝语意学

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

时间:2022-12-13 14:44:06浏览次数:38  
标签:初始化 函数 Point 语意 析构 基类 拷贝 构造函数

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

纯虚函数的存在

在虚基类的时候一定要将析构函数声明为虚函数。编译器在调用派生类析构函数会采用静态调用的方式一层一层的调用每一个虚基类的析构函数,如果缺乏一个基类析构函数的定义会导致链接失败(Linux g++ 编译会出现 undefined reference),并且不要将虚析构函数声明为pure的,编译器没有足够的能力合成一个pure virtual destructor

不要将一个抽象基类声明为const

继承体系下的对象的构造

编译器会按照继承体系去扩充构造函数,大致的扩充操作如下:

  1. 成员初始化列表中的数据成员会被放进构造函数体中,以成员声明的顺序为顺序。

  2. 如果成员没有出现在初始化列表中,但是含有默认构造函数,该默认构造函数必须被调用。

  3. 在以上步骤之前,如果有虚函数,一定要先初始化vptr.

  4. 在以上步骤之前,上一层的基类的构造函数被调用,以基类的声明顺序为顺序:

    • 如果基类处于成员初始化列表中,任何显式指定的参数必须被传递进去
    • 如果基类没有处于成员初始化列表,但是含有默认构造函数就调用默认构造函数。
    • 如果基类是多重继承下的第二个或者后继的基类,就要调整this指针的顺序。
  5. 在以上步骤之前,虚基类的构造函数必须被调用,按照从左到右,由最深到最浅的顺序:

    • 如果基类处于成员初始化列表中,任何显式指定的参数必须被传递进去。如果基类没有处于成员初始化列表,但是含有默认构造函数就调用默认构造函数。
    • 每一个虚基类的子类的偏移位置在执行期必须被存取。

下面这个例子描述了构造函数的扩充:

class Point {
public:
  Point(float x = 0.0, float y = 0.0);
  Point(const Point&);
  Point& operator=(const Point&);
  virtual ~Point();
  virtual float z() { return 0.0; }
private:
  float _x, _y;
};

class Line {
  Point _begin, _end;
public:
  Line(const Point& begin, const Point& end) : _begin(begin), _end(end) {}
};

// Line的构造函数会被编译器扩充为
Line* Line::Line(Line *this, const Point &begin, const Point &end) {
    this->_begin.Point::Point(begin);
    this->_end.Point::Point(end);
}

虚指针初始化语意学

虚指针在构造函数中何时被初始化?

在基类构造函数调用操作之后,但是在程序员提供的代码或是成员初始化列表所列的成员初始化操作之前。

虚指针必须被设定的两种情况:

  • 当一个完整的对象被构造器起来时。
  • 当一个子对象的构造函数调用一个虚函数时。

对象复制语意学

一个类的拷贝赋值运算符,在一下情况不会出现bitwise copy 语意:

  • 当类内含有一个成员对象,并且其class 有一个拷贝赋值运算符
  • 当一个类的基类有一个拷贝赋值运算符
  • 当一个类声明任何虚函数
  • 当一个类继承自一个虚基类的时候

对于棱形继承中的拷贝,编译器需要抑制基类的重复拷贝,通过添加额外的参数most_derived 来抑制,但是尽可能的不允许一个虚基类的拷贝操作,不要在任何虚基类中声明数据。

析构语意学

如果一个类没有析构函数,只有在类内含有一个对象成员拥有析构函数的情况下编译器才会自动合成一个出来。

析构函数的执行顺序:

  1. 析构函数的本体首先执行
  2. 如果class 有一个的成员是一个类,并且有构造函数,按照声明的顺序的相反顺序执行析构函数
  3. 如果一个对象含有一个虚指针,首先重设vptr指向基类的virtual table
  4. 如果有任何直接的非虚基类拥有析构函数,按照声明顺序的相反顺序被调用
  5. 如果有任何虚基类有析构函数,当前类按照原来构造顺序的相反顺序调用析构函数。

析构函数的底层实现策略时维护两份析构函数实例:

  1. 一个complete object 实例,总是设定好vptr , 并调用virtual base class destructors
  2. 一个base class subobject 实例,除非在析构函数中调用一个虚函数,否则绝不会调用virtual base class的析构函数并设定虚指针。

标签:初始化,函数,Point,语意,析构,基类,拷贝,构造函数
From: https://www.cnblogs.com/gxsoar/p/16978735.html

相关文章

  • 构造和析构
    题目内容:设计学生类,数据成员包括学号、姓名、年龄、成绩;成员函数有构造函数、析构函数。定义带默认参数值的构造函数,默认值为:2021001,“Lili”,19,89.5。定义析构函数,析构时......
  • C#深拷贝方法
    概述 为什么要用到深拷贝呢?比如我们建了某个类Person,并且实例化出一个对象,然后,突然需要把这个对象复制一遍,并且复制出来的对象要跟之前的一模一样,来看下我们一般......
  • SCP后台远程拷贝
    SCP后台远程拷贝需求如果直接使用scp拷贝文件,终端断开以后,scp命令就停止了,容易拷到一半就失败了,需要重新拷贝,因此直接后台运行scp命令。步骤正常scp命令运行拷贝scp......
  • cpp浅拷贝和深拷贝
    一、浅拷贝Shallowcopy:ifthefieldisapointertosomeobject,theaddressofthepointeriscopiedratherthanitscontents.(浅拷贝:数据域是一个指针,只拷指......
  • 记录下关于微信h5支付那点事儿(百分之80拷贝官方)
    LZ-Says:困意上来,感觉简直痛不欲生~生亦何欢~!!!前言这俩天在玩微信的H5支付,不得不说,腾讯出品,Enmmm,懂就好。。。原想着这是一件很easy的东西,WebView加载一个地址不久好了,enmmm......
  • .NET 实现实体对象深拷贝(克隆/复制)的几种方法
    一、浅拷贝:指对象的字段被拷贝,而字段引用的对象不会被拷贝,拷贝对象和原对象仅仅是引用名称有所不同,但是它们共用一份实体。对任何一个对象的改变,都会影响到另外一个对象。......
  • Object.assign()之浅拷贝解析
    1.做前端开发时遇到一个对象拷贝的问题,当时我把需要拷贝的对象使用Object.assign方法复制了一份,但是再对拷贝出来的对象处理后出现一些问题,如下:constoriginalObject={......
  • 23. 深浅拷贝
    概念浅拷贝:只拷贝最外面一层的数据;更深层次的对象,只拷贝引用。深拷贝:拷贝多层数据;每一层级别的数据都会拷贝。总结:拷贝引用的时候,是属于传址,而非传值。深拷贝会......
  • 彻底理解Python中浅拷贝和深拷贝的区别
    OverridetheentrypointofanimageIntroducedinGitLabandGitLabRunner9.4.Readmoreaboutthe extendedconfigurationoptions.Beforeexplainingtheav......
  • JavaScript:对象:如何复制一个对象?浅拷贝与深拷贝
    回顾一下,我们对传参的讨论,对象的传参是引用传递,我们传递的是对象数据所在的内存地址;那么无论我们怎么去赋值,所有变量指向的都是同一块内存;如上图所示,无论我去使用哪个变......