4.2对象的初始化和清理
-
生活中多有电子产品基本都会有出厂设置,在某天我们不用的时候会删除一些自己的形象数据保证安全
-
c++中的面向对象来与那与生活,每个对象都会有初始化设置以及对象销毁前的清理数据的设置
4.2.1构造函数和析构函数
对象的初始化和清理也是两个非常重要的安全问题
一个对象或者变量没有初始状态,对其使用后果是未知的
同样使用完一个对象或变量没有及时清理也会造成一定的安全问题
c++利用构造函数和析构函数结局上述问题,这两个函数会被编译器自动调用,完成对象初始化和清理工作,对象的而初始化和清理操作是编译器强制要我们做的因此如果我们不提狗那个构造函数和析构函数编译器会提供 编译器提供的构造函数和析构函数是空实现
-
构造函数:主要作用在于创建对象时为对象的成员属性赋值,由编译器自动调用,无需手动调用
-
析构函数:主要作用于对象销毁前系统自动调用,执行一些清理工作
构造语法 :类名(){}
-
构造函数,没有返回值也不写void
-
函数名称与类名相同
-
构造函数有参数,因此可以发生重载
-
程序在调用对象时会自动调用构造,无需手动调用,而且只会调用一次
析构函数:~类名(){}
-
析构函数没有返回值也不写void
-
函数名称与类名相同,在名称前写上~
-
析构函数不可以有参数因此也不可以发生重载
-
程序在对象销毁前会自动调用析构函数,无需手动调用而且只会调用一次;
4.2.2 构造函数的分类和实现
分两类:
一.按有无参数分
有参数
无参数
二.按类型分
普通构造
拷贝构造
三种调用方法:
括号法
显示法
隐式转换法
4.2.3 拷贝构造函数调用时机
-
使用一个已经创建完毕的对象来初始化一个新的对象
-
值传递的方式给函数参数传值
-
拷贝构造是开辟了新空间的而不是把地址传过去;
-
开辟了新的对象然后把原来对象的值赋给了新的对象所以改变新对象的值不会导致原来对象的值的改变。
-
值方式返回局部对象;
4.2.4构造函数的调用规则
c++编译器至少会给一个类添加三个函数
-
默认构造函数(无参,函数体为空)
-
默认析构函数(无参2,函数体为空)
-
默认拷贝构造函数对所有属性进行值拷贝(值拷贝)无论写不写都会有进行拷贝
构造函数调用规则如下 :
-
如果用户定义有参构造函数,则c++不再提供无参构造函数,但是会提供默认拷贝构造
-
如果用户定义拷贝构造函数,c++不会再提供其他构造函数
* 如果写了拷贝构造但是没有自己写无参构造就会导致报错因为系统也没有进行分配
因为在进行拷贝构造时必须先将建造一个对象而这个对象必须无参或者有参构造所以报错。
因此在写了拷贝构造函数有一定要写普通构造函数,而写了普通构造函数不一定要写拷贝构造函数;
4.2.5深拷贝和浅拷贝
大坑
浅拷贝:简单的复制拷贝操作//就是编译器提供的简单的拷贝
深拷贝:在堆区重新申请空间,进行拷贝操作
系统提供的拷贝构造函数只能进行浅拷贝会使两个对象的同一个属性指向同一个地址手动释放的时候会导致重复释放。
delete m_height; m_height = NULL;//m_Height=NULL只是将指针为空不再指向堆上的内存 delete m_Height才是释放指针指向的内存
栈区开辟的对象遵循先进后出的规律所以会先释放后一个对象的身高的内存地址该地址将不存在,而后将该指针上存储的地址改为NULL;而后对第一个对象进行释放操作(两个不同的指针指向了同一个内存空间)
想要不重复释放需要自定义一个拷贝构造函数来进行深拷贝;重新在堆区申请一块内存这块内存上存放需要拷贝的数据值;
(先释放p2后释放p1的原因)指针放在栈区,指针所指的值存放在堆区,释放的是堆区中的值,,p1的m-height指针还是存在的只是指针上的数据变为空即指向空地址;
如果属性有在堆区进行开辟的一定要自己提供一个拷贝构造函数,防止浅拷贝带来的重复释放内存的问题
4.2.6初始化列表
c++提供了初始化列表语法用来初始化属性
语法 构造函数() :属性1(值1),属性2(值2)················{ }
注意冒号的位置
4.2.7 类对象作为类的成员
c++类中的成员乐意是另一个类的对象我们称该成员为对象成员
class A{}; class B { A a; };
B类中有a作为对象时,a为对象成员
讨论AB 构造和析构的顺序:当其它类作为本类成员,构造时候先构造类对象,再构造自身
析构是先析构自身后析构自身内部其他类的对象(遵循栈的规律先进后出)
4.2.8静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:
-
静态成员变量
-
所有对象共享同一份数据
-
在编译阶段分配内存程序还没有运行之前就分配内存,在全局区
-
类内声明类外初始化静态变量在全局区,所以不可以在类内初始化
静态成员变量不属于某个对象,因为所有成员都共享同一份数据
因此静态成员变量有两种访问方式
-
通过对象进行访问
-
-
静态成员函数
-
所有对象共享同一个函数
-
静态成员函数只能访问静态成员变量
-