c++学习之构造函数和析构函数篇

来源:互联网 发布:cs起源 知乎 编辑:程序博客网 时间:2024/05/17 17:42

一、构造函数

1.对象结构:

首先了解内存分区,如下图所示:

2.对象结构举例说明:

下面定义了一个汽车的类,在类被实例化之前是不会占用栈或堆中内存的,当被实例化后,比如实例化了三个对象,car1、car2、car3,这每一个对象都会在栈上开辟内存,来存储各自的数据,但它们各有一份变量,占据不同的内存,而逻辑代码只编译出了一份,放在代码区,当需要的时候代码区中的代码供所有的对象进行使用,谁需要的时候就去调用它,找到相应的代码入口就可以执行相应的程序了。


3.对象初始化:

如果不对对象初始化,我们就不知道car1、car2、car3在内存中是如何存储的,就没法对其进行预想的逻辑运算。为了初始化对象,可以声明一个普通的init函数,用对象调用,但是这样容易重复初始化和忘记初始化,为避免这种情况发生,C++推出了一种特殊的函数,叫构造函数。它由如下特点:

(1)构造函数在对象实例化时被自动调用,且仅被调用一次,把初始化代码写到构造函数里面即可实现对象初始化。

(2)构造函数与类名重名

(3)构造函数没有任何返回值

(4)构造函数可以有多个重载形式,

(5)实例化对象时仅用到一个构造函数

(6)当用户没有定义构造函数时,编译器自动生成一个构造函数,这个自动生成的构造函数内不做任何事情,一旦用户定义了构造函数,编译器便不再生成构造函数。

(7)构造函数可以有参数也可以无参数,当所有参数都有默认值时,调用时也和无参数的构造函数调用方式一样,可以不加任何参数,这个时候它也叫默认构造函数。

注意:什么是默认构造函数?在使用时不需要传递参数的构造函数就是默认构造函数。

注意:虽然可以给构造函数的参数设置默认值,但是注意不能和其他重载构造函数在调用的时候引起冲突,即调用方式一样。

注意:默认值只是在函数声明的时候加,函数定义的时候不用写出默认值,和其他函数写法一致即可。

注意:一个类可以没有默认构造函数,有别的构造函数(有参且并不是全部有默认值)也可以实例化对象


4.构造函数的初始化成员列表,其特点如下:


(1)初始化成员列表先于构造函数执行,编译器先给初始化成员列表里面的成员变量赋值,再执行构造函数里面的代码,程序代码效率高

(2)初始化列表只能用于构造函数

(3)初始化列表可以同时初始化多个数据成员

(4)初始化成员列表存在必要性:类里面const修饰的常量成员变量必须用初始化列表的方式初始化。




5.拷贝构造函数


上图中实例化对象的三种方式,只会调用一次默认的构造函数,只有第一种实例化方式才会调用,后面两种会调用默认的拷贝构造函数。它有如下特点:

(1)定义格式:类名(const 类名& 变量名)例:Student(const Student& stu){}

(2)如果没有自定义拷贝构造函数则系统自动生成一个默认的拷贝构造函数

(3)当采用直接初始化(括弧的方式)或复制初始化(等号复制的方式)实例化对象时,系统会自动调用拷贝构造函数

注意:普通构造函数和拷贝构造函数后面都可以跟初始化成员列表

二、析构函数

1.析构函数功能

如果说构造函数是对象来到世上的第一声哭泣,析构函数就是临终遗言,在对象销毁时自动调用,完成的工作是归还系统资源,收拾最后残局,析构函数是在类名前加一个小尾巴,~Student(){}不允许加任何参数。析构函数的唯一功能就是释放资源。如下图所示,


2析构函数特点:

(1)如果没有自定义的析构函数则系统自动生成

(2)析构函数在对象销毁时会自动调用,此时最适合释放堆中内存。与其相对应的,构造函数实在对象实例化时自动调用

(3)析构函数没有返回值、没有参数、也不能重载

(4)不管是通过什么方式,普通构造函数还是拷贝构造函数生成的实例对象,销毁时都会调用析构函数。

(5)可以从栈中或者堆中实例化对象,都会调用构造函数,但是在栈中实例化的对象在作用域范围运行结束以后会自动调用析构函数来销毁对象,但是从堆中定义的对象,必须通过delete 来显示销毁对象,调用delete  对象,这句话也会调用析构函数。

三、对象声明周期

对象实例化时,先向系统申请内存,然后给初始化成员列表赋值,然后执行构造函数,构造函数执行完以后,开始进行正常的逻辑运算,运算终止,进行到对象销毁环节,对象销毁时,先执行析构函数,然后释放内存;可见申请的资源最终还是要归还的。


0 0