新手c++之类与对象(中)

类的六个默认成员函数

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

也就是一个类不论有没有成员都有至少六个函数声明

这次我们主要介绍 构造函数 析构函数 拷贝构造函数  其中构造和析构负责初始化和清理  拷贝构造函数负责拷贝构造函数

构造函数

构造类似于init功能 在对象整个生命周期内只调用一次。

特征

1. 函数名与类名相同。

2. 无返回值。

3. 对象实例化时编译器自动调用对应的构造函数。

4. 构造函数可以重载。

其中特别要注意的是构造函数不是创建对象 而是初始化对象

在这个类中我们定义了两个构造函数 这两个构造函数重载 其中一个无参 一个有参 

在开对象是 不输入任何值会调用无参构造 产生随机值  在后面的括号中输入日期 则通过有参初始化正常

我们也可以将有参和无参通过缺省函数合并起来 写成一个构造函数

这时我们可以看到一个缺省的构造函数可以实现多种开对象的功能 这里可以很灵活的使用一种构造函数来开创多种对象

且在写全缺省之后也不会再去写缺省 虽然这两种构成重载 但是在使用时会产生歧义

5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦 用户显式定义编译器将不再生成。

这是默认生成的会产生随机值 这里无论是随机值 还是 0 都不必疑惑 因为编译器的不同 这里的处理也是不同的 

这里为什么会生成随机值  C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型 如int char  longlong 包括指针 等都是 内置类型

这里编译器对内置类型是不会进行处理的 而自定义类型则是可以通过调用这个类中的构造函数去处理

系统默认生成的无参的构造函数和无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。 注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为 是默认构造函数。由于只能存在一个若是我们写了自己的无参或者全缺省构造函数 系统就不会再生成 若是我们没有写构造函数 系统就会替我们自动生成无参构造函数

注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在 类中声明时可以给默认值。

而且在有缺省值的前提下对创建的对象进行构造  在执行过程中会先将缺省值赋给对象 再讲初始化的值覆盖给对象

析构函数

与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

注意的是这里的资源清理工作不是销毁对象 是对对象的残余资源的清理

特性

 析构函数名是在类名前加上字符 ~。

 无参数无返回值类型。

 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载

 对象生命周期结束时,C++编译系统系统自动调用析构函数。

这里写过的日期类是不需要进行多余资源的清理的 不需要自己写析构函数

而malloc 等开创空间的是我们需要写析构函数来进行资源的清理的

我们分别在构造函数和析构函数中加入了输出语句标志  每次调用构造和析构函数时就会输出相应语句         如上图

析构函数也可以显示调用 这里相当于destroy两次 那么为什么会没报错呢?

这是因为在写析构函数时加入了if语句进行判断 防止出错

关于编译器自动生成的析构函数,是否会完成一些事情呢?

内置类型不作处理 

自定义类型去调用它的析构  (这和构造函数处理事类似的)

在上图中如果没有写析构函数 系统自动生成的默认析构是不会去清理_array 的空间的  这时就会发生内存泄漏  这是非常可怕的 内存泄漏是不会报错的

实践中总结:
1、有资源需要显示清理,就需要写析构。如:Stack List有两种场景不需要显示写析构,默认生成就可以了2、
没有资源需要清理,如:Dated、
b、内置类型成员没有资源需要清理。剩下都是自定义类型。如:MyQueue

在这个myqueue中 s1 和s2是自定义类型 会去调用相对应自定义类型的构造和析构   而_size是内置类型  而且没有资源需要清理 所以myqueue类型中不需要去主动定义析构函数

拷贝构造函数:用同类型的对象拷贝初始化

只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用。

拷贝构造是构造里面的一个细分 子分类

特征

拷贝构造函数是构造函数的一个重载形式。

拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用

因为传自定义类型 传值传参需要调用拷贝构造完成  如果拷贝构造函数不进行引用 就会进行无穷的拷贝构造  

如何取向这种调用拷贝构造 就是取消传值传参 改为传址 

传址有两种方式 一种是指针 一种是引用

在标准的拷贝构造函数中 参数会用const修饰 防止在赋值出现错误

这时就会及时报错

这是如果不加const修饰 就不会产生预期所能达到的效果

若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

这是一种普通构造 不是拷贝构造 普通构造不会影响拷贝构造  没有生成拷贝构造依旧按系统生成的默认拷贝构造函数使用

date 类能通过系统默认生成的拷贝构造 不需要自己定义

但是stack类就无法用默认拷贝构造进行拷贝

通过默认拷贝 会使得两个array都指向同一个空间这样会引发一系列的问题

1.当s1数组发生改变时 s2也会被动改变

2.当s1push一个值时 s1的size加1但是s2的空间大小发生改变 但是记录s2的size却保持不变 产生错误信息

3.当进行析构 同一个空间会发生两次析构 导致系统崩溃

因此我们需要深拷贝

总结一下
如果没有管理资源,一般情况不需要写拷贝构造,默认生成的拷贝构造就可以。如:Date

如果都是自定义类型成员,内置类型成员没有指向资源,也类似默认生成的拷贝构造就可以。如:MyQueue

一般情况下,不需要显示写析构函数,就不需要写拷贝构造
如果内部有指针或者一些值指向资源,需要显示写析构释放,通常就需要显示写构造完成深拷贝。如:Stack Queue List等

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值