C++杂记——构造函数

文章目录

    • [default constructor](#default constructor)
    • [copy constructor](#copy constructor)
    • 参考

default constructor

当编译器需要构造函数的时候,而类本身没有定义构造函数时,会被合成出来,被合成的构造函数只会执行编译器所需的动作。

带有default constructor的成员对象

如果一个类没有任何构造函数,但它内含一个成员对象,而这个成员对象有默认构造函数,那么这个类的隐式默认构造函数就是"nontrival"的,编译器需要为该class合成出一个默认构造函数。不过这个合成操作只会在constructor真正需要被调用时才会发生。

如果一个类A 内含一个或一个以上的成员类对象,那么类A的每一个构造函数必须调用每个成员类的默认构造函数。编译器会扩张已存在的constructors,在其中安插一些代码,使得用户代码被执行前,先调用必要的默认构造函数。

如果是多个成员类对象,C++要求以成员在类中声明顺序来调用各个构造函数。这一点由编译器完成,它为每一个constructor安插程序代码,以成员声明顺序调用每一个成员所关联的默认构造函数。这些代码将安插在用户代码前面。

带有default constructor的基类

如果一个没有任何构造函数的类派生自一个"带有默认构造函数"的基类,那么这个派生类的默认构造函数会被是为nontrival,并因此需要被合成出来。它将调用上一层基类的默认构造函数(根据它们的声明顺序)。对一个后继派生的类而言,这个合成的构造函数和一个"被显式提供的默认构造函数"没有什么差异。

如果已经提供了多个构造函数,但其中都没有默认构造函数。编译期会扩张现有的每一个构造函数,将"用以调用所有必要之默认构造函数"的程序代码加进去。他不会合成一个新的默认构造函数,因为其他"由用户所提供的构造函数"存在的缘故。如果同时也存在着"带有默认构造函数"的成员类对象,那些默认构造函数也会被调用------在所有基类构造函数都被调用之后。

带有一个虚函数的类

另有两种情况,也需要合成出默认构造函数:

  • 类声明(或继承)一个虚函数
  • 类派生自一个继承串链,其中有一个或更多的虚基类(virutal base class)

不管哪一种情况,由于缺乏由用户声明的构造函数,编译期会详细记录合成一个默认构造函数的必要信息

下面两个扩张行为会在编译期间发生:

  • 一个virtual function table会被编译期产生出来,内放类的virtual functions地址
  • 在每一个类对象中,一个额外的pointer member(即vptr)会被编译期合成出来,内含相关的类vtbl的地址

带有一个虚基类的类

必须使vritual base class在其每一个derived class object中的位置,能够于执行期准备妥当。

总结

有4种情况,会造成编译期必须为未声明constructor的类合成一个default constructor.

C++标准把那些合成物称为implicit nontrivial default constructors.

被合成出来的constructor只能满足编译期(非程序)的需要。它之所以能够完成任务,是借着"调用member object或base class的default constructor"或是"为每一个object初始化其virtua fuction机制或virtual base class机制"而完成的。至于没有存在那4种情况而又没有声明任何constructor的class,我们说它们拥有的是implicit trivial default constructors,它们实际上并不会被合成出来。

在合成的defaullt constructor中,只有base class subobjects和member class objects会被初始化。所有其他的nonstatic data member(如整数、整数指针、整数数组等等)都不会被初始化。这些初始化操作对程序而言或许有必要,但对编译期而言则非必要。如果程序需要一个"把某指针设为0"的default constructor,那么提供它的人应该是程序员。

copy constructor

如果一个类没有提供一个explicit copy constructor, 此时以另外一个对象赋值时,其内部是将每个成员对象的值从一个对象拷贝到另一个对象。这种可以自动进行的拷贝过程称为默认拷贝构造。

一个对象可以用两种方式复制得到:

  1. 被初始化,即被拷贝构造
  2. 被指定(assignment),即拷贝赋值
    C++标准把copy constructor分为trivial和nontrivial的。只有nontrivial的实例才会被合成于程序中。决定一个copy constructor是否为trivial的标准在于class是否展现出所谓的"bitwise copy semantics(位逐次拷贝)"。

下面四种情况下,一个类不会展现出"bitwise copy semantics":

  1. 当类内含一个成员对象而该对象的类声明有一个copy constructor时(不论是被类设计者显式声明,或是被编译器合成)
  2. 当类继承自一个基类,而后者存在一个copy constructor时(不论是被显式声明或是被合成的)
  3. 当class声明一个或多个virtual functions时
  4. 当class派生自一个继承串链,其中有一个或多个virtual base classes时

前两种情况下,编译期必须将member或者base class的"copy constructors调用操作"安排到被合成的copy constructor中。

在上面四种情况下,类不再保持"bitwise copy semantics",而且default copy constructor如果未被声明的话,会被视为nontrivial。这种情况下,如果缺乏一个已声明的copy constructor,编译器为了正确处理"以一个class object作为另一个class object的初值",必须合成出一个copy constructor。

参考

C++杂记------返回值优化(RVO,Return Value Optimization)、具名返回值优化 (NRVO,Named Return Value Optimization)

相关推荐
rainbow688910 小时前
EffectiveC++入门:四大习惯提升代码质量
c++
秋邱10 小时前
用 Python 写出 C++ 的性能?用CANN中PyPTO 算子开发硬核上手指南
开发语言·c++·python
我在人间贩卖青春10 小时前
C++之析构函数
c++·析构函数
我在人间贩卖青春11 小时前
C++之数据类型的扩展
c++·字符串·数据类型
wangjialelele11 小时前
平衡二叉搜索树:AVL树和红黑树
java·c语言·开发语言·数据结构·c++·算法·深度优先
苏宸啊11 小时前
C++栈和队列
c++
森G11 小时前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
橘颂TA12 小时前
【测试】高效浏览器操作:基础功能与优化设置大全
c++·功能测试·职场和发展·测试·web测试
一只小小的芙厨12 小时前
寒假集训笔记·以点为对象的树形DP
c++·算法
艾莉丝努力练剑12 小时前
hixl vs NCCL:昇腾生态通信库的独特优势分析
运维·c++·人工智能·cann