SYSU程设c++(第六周)类的非静态成员初始化、默认成员初始化器、成员初始化器列表、c++内存布局、拷贝构造函数、深复制策略、重写“=”操作

时间:2021-08-07 01:20:03

类的非静态数据成员初始化:

•类的非静态成员初始化手段:

  ① 通过默认成员初始化器 ② 用构造函数的成员初始化器列表 ③ 在构造函数体内进行赋值操作。

默认成员初始化器:

        包含花括号等号初始化器,例如:SYSU程设c++(第六周)类的非静态成员初始化、默认成员初始化器、成员初始化器列表、c++内存布局、拷贝构造函数、深复制策略、重写“=”操作

初始化器列表:

        和构造函数在一起,初始化器列表在构造函数申明后以冒号开头,后跟一系列以逗号分隔的成员初始化器,再之后才是构造函数的函数体,例如:

SYSU程设c++(第六周)类的非静态成员初始化、默认成员初始化器、成员初始化器列表、c++内存布局、拷贝构造函数、深复制策略、重写“=”操作

        使用初始化器列表时,首先会按声明顺序初始化成员,然后执行构造函数函数体。

成员初始化器:

        成员初始化器包括默认成员初始化器初始化器列表

必须使用成员初始化器的情况:

        1.常量成员,因为常量只能初始化不能赋值,所以要使用初始化器

        2.引用成员,引用必须在定义的时候初始化,并且不能重新赋值,所以也要使用初始化器

用初始化列表时数据成员初始化的顺序:

        是按照它们在类中声明的顺序进行初始化的,而不是按照它们在初始化器列表出现的顺序初始化的。

        出错例子 :

SYSU程设c++(第六周)类的非静态成员初始化、默认成员初始化器、成员初始化器列表、c++内存布局、拷贝构造函数、深复制策略、重写“=”操作

         这里i的值是未定义的。因为虽然j在初始化器列表里面出现在i前面,但是i先于j 定义,所以先初始化i,而i由j初始化,此时j尚未初始化,所以导致i的值未定义。

        •因此要写代码养成按照成员声明的顺序进行初始化的好习惯

类的非静态数据成员的初始化的综合例子:

SYSU程设c++(第六周)类的非静态成员初始化、默认成员初始化器、成员初始化器列表、c++内存布局、拷贝构造函数、深复制策略、重写“=”操作

C++内存布局:

        1)静态存储区域。这块内存在程序编译的时候就已经分配好,在程序的整个运行期间都存在。例如全局变量,static 变量。

        2)。函数在被执行时内部局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。

        3)堆,亦称动态内存分配。程序在运行的时候用malloc 或new 申请的存在堆上

        结构体存储在栈中;类的实例化可以存储在栈中,也可以存储在堆中

拷贝构造函数:

效果:用一个已存在的该类对象初始化新创建的对象。

        如在已经定义了obj对象的前提下,创建同类的objb对象:

        C objb(obj);  //或 C objb = obj ; 两者等价(注意:不是赋值运算

定义形式:形参类型为该类类型本身且参数传递方式为按引用传递。

        比如C::C(const C& obj); 

          • 该参数传递方式为按引用传递,避免在函数调用过程中生成形参副本。

          • 该形参声明为const,以确保在拷贝构造函数中不修改实参的值

存在性:每个类都必须有拷贝构造函数:

        • 用户可根据自己的需要显式定义拷贝构造函数。

        • 若用户未提供,则该类使用由系统提供的缺省拷贝构造函数

        • 可用=default,也可用 =delete 弃置该函数。

        • 缺省拷贝构造函数会按照初始化顺序,对对象的各基类和非静态成员进行完整的逐成员复制,完成新对象的初始化。即逐一调用成员的拷贝构造函数, 如果成员是基础类型,则复制值。
 

拷贝构造函数的调用:

       1. 显式调用:

                用声明 C objb(obj) 或 new C(obj) 会触发拷贝构造函数

       2. 隐式调用:

                •函数的形参是对象时。把对象作为实参,传递给被调函数的形参对象,会调用拷贝构造函数。 (注意形参对象生存期结束被撤销时,还会调用析构函数)

                •(理论上)函数返回结果时对象时。会自动生成一个临时对象来保存函数返回结果,创建此临时对象用到拷贝构造函数。 (注意当函数调用表达式结束后,撤销该临时对象时,会调用析构函数) 

                但实际g++有编译优化(叫复制省略),即将函数返回的临时对象直接写在接受者的地址上,不再自动创建临时对象,因此g++编译优化下不会调用拷贝构造函数。 

需要自定义拷贝构造函数的情况:

        (对于不含指针成员的类,使用编译器的默认拷贝构造函数即可),但只要含指针成员,就要用自定义拷贝构造函数。

        因为缺省拷贝构造函数使用浅复制策略,浅拷贝只复制成员指针的值,而不复制指向的对象实体,导致新旧对象成员指针指向同一块内存。

        含指针成员的类应重写以下内容:

                • 用深复制策略,在拷贝构造函数中给指针分配内存

                • “=” 操作重写,完成对象深复制策略

深复制策略:(用new分配内存给指针)

SYSU程设c++(第六周)类的非静态成员初始化、默认成员初始化器、成员初始化器列表、c++内存布局、拷贝构造函数、深复制策略、重写“=”操作

重写“=”操作:(注意这个“=”不是赋值运算)

SYSU程设c++(第六周)类的非静态成员初始化、默认成员初始化器、成员初始化器列表、c++内存布局、拷贝构造函数、深复制策略、重写“=”操作(保证每个地方都是深复制)

SYSU程设c++(第六周)类的非静态成员初始化、默认成员初始化器、成员初始化器列表、c++内存布局、拷贝构造函数、深复制策略、重写“=”操作