侧边栏壁纸
博主头像
赵东阳的个人网站

行动起来,活在当下

  • 累计撰写 20 篇文章
  • 累计创建 8 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录
C++

构造函数语义学

温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

构造函数语义学1

  1. 构造函数

  2. 拷贝构造函数

  3. 赋值操作运算符


    构造函数

    广泛存在的两个误解:

    image-20220314110929617

构造函数,构造类的对象,填充初始值。给对象的赋初始值应该是程序员的责任。

image-20220314103136600

只要满足上面的四个条件,默认构造函数就不会被构建。

  1. 没有虚函数,没有虚基类,类中没有虚函数,没有虚表指针。
  2. 没有非静态的数据成员,在声明的地方未被初始话。(去设置初始值
  3. 所有直接继承的基类,他们有无用的默认构造函数。(需要生成构造函数去调用父类的构造函数完成初始话
  4. 如果所有非静态的数据成员都是类,每一个类都具有自己的trivial defualt constructor

什么情况会生成默认构造函数?四条会产生构造函数的情况

image-20220314104058270

如上图,构造函数会设置虚表指针的值(却不会设置变量的值,这是程序员的责任

当我们用等号或大括号进行初始化 ,会合成默认构造函数。

image-20220314104604093

上图中,3D会生成构造函数去调用2d的构造函数完成初始化。

image-20220314105406510

需要生成构造函数来完成对有用的构造函数调用来完成初始化。

什么时候会产生构造函数呢,

  • 需要进行初始化,而程序员又没办法进行,如虚表指针的生成。
  • 我们使用大括号或等号给数据成员赋值,编译器会使用构造函数完成初始化赋值
  • 继承的基类有默认构造函数,我们在使用基类成员时,自然要为他们完成初始化
  • 也就是说,只要类成员存在有效的默认构造函数,那就要生成一个构造函数去调用它们

**构造函数语义学2 **

基类和数据成员的初始化时机

一旦由程序员声明了构造函数,那么编译器在任何情况下都不会合成默认构造函数。

所以编译器只能扩充每一个构造函数,去调用父类的默认构造函数。

image-20220314111514585

**问题是,编译器会把扩充安排在什么地方呢?**之前,之后,还是我们自己的代码之间呢?

答案是,编译器会把扩充放在用户代码之前,因为用户代码可能立刻用到父类的成员,所以必须先初始化。

如上图中,3D的指针被强制转换成2d,用来调用默认构造函数。

基类和数据成员的初始化实际按照数据成员的声明顺序,调用其默认构造函数。

image-20220314113006861

当我们采用参数列表来调用构造函数时,会直接调用拷贝构造函数,节省了一次成员构造函数的初始化,可能会造成性能的差异。当然,对于基本数据类型如:char,int由于没有默认构造函数,所以,无论采用哪种方式,效率都是一样的。当存在拷贝构造函数时,差异就会出现。

image-20220314113600764

上图的本意是,把j的值给val,然后令i等于J。但是,由于含函数中i和j的声明顺序,编译器实际上不是这样作的。

拷贝构造函数

用到拷贝构造函数的三种情形:

image-20220314114339477

  1. 对象被创建的时候赋初值(而不是两个已经存在的对象
  2. 函数用对象做参数,局部对象的拷贝,产生了新的副本
  3. 当函数的返回值是一个对象。也会产生局部对象的拷贝,也是通过拷贝构造函数来进行的(所以要返回指针?

当一个对象创建出来的时候,基于另外一个对象。

那么我们就有几个问题,

  1. 何时需要程序员提供拷贝构造函数?
  2. 编译器合成拷贝构造函数的条件?
  3. 编译器扩充拷贝构造函数的规则?(编译器 可能会对程序员提供的拷贝构造函数进行补充

image-20220314115352721

如果可以直接按位拷贝,那么编译器不会生成拷贝构造函数。但是我们对指针进行考虑,我们不希望两个指针都指向这个字符串。所以我们需要提供拷贝构造函数。

看似好像都符合按位拷贝的要求,其实也有四种情况:

  1. data member有拷贝构造函数
  2. base class有拷贝构造函数
  3. 类有虚函数(需要设置正确的虚表指针
  4. 继承自虚基类

即:类对象的一部分需要被拷贝函数正确的设置

编译器何时会合成拷贝构造函数?

image-20220314121035253

只有满足上述三个条件,编译器才不会合成拷贝构造函数

  1. 类函数没有虚函数,没有虚基类,并且直接继承的基类,没有拷贝构造函数
  2. 类X的非静态数据成员,对应的类没有拷贝构造函数
  3. 用户没有提供拷贝构造函数

只要一个不满足,就会合成构造函数

编译器扩充拷贝构造函数的规则?

目的都是:为了确保类对象的完整性。

小结

一切的目的都是 :一个类在声明的时候是完整的。

image-20220314122602058
c++ 的核心是以对象模型为支撑的面向对象模型?

0

评论区