1.类的6个默认成员函数
2.构造函数
3.析构函数
4.拷贝构造函数
5.赋值操作函数
6.默认拷贝构造函数与赋值运算符重载函数
7.const成员函数
8.取地址及const取地址操作符重载
初接触类的时候,我们写过空类,那么空类真的是什么都没有吗?其实不是的
在我们不人为实现的时候,任何类都会有如下6个默认成员函数
2.1概念
对于类A,我们如果想对A的实例化对象设置内容可以通过setval来实现,但我们要先创建出A,
再进行调用,这样过于繁琐,那么构造函数就是一种特殊的成员函数,名字与类名相同且没有返回类型,创建对象的时候编译器会自动调用,并且在一个对象的生命周期内只调用一次
2.2特性
构造函数是特殊的成员函数,虽然名字叫构造,但并不是开辟空间而是对成员的初始化
其特征如下:
1.函数名与类名相同
2.无返回值
3.对象实例化时编译器自动调用对应的构造函数
4.构造函数可以重载
如果没有人为给出,编译器默认生成无参默认构造函数,人为给出任意形式的构造函数,编译器都不会生成默认无参构造函数
2.3 初始化列表
前面我们说构造函数只是对成员的初始化,初始化的这一操作我们可以在函数内直接实现(这是我们所熟知的),但是C++提供了另一种效率更高的方式,即初始化列表
使用方式如下
需要注意的是:
1.初始化列表的赋值顺序为declare的顺序,即 _x , _y ,_z 哪怕我们代码顺序为_z,_y,_x仍然会以declare顺序进行初始化,明晰这一点可以避免一些不必要的bug
2.初始化列表这一操作为defination,函数体内操作为assignment
2.1概念
C语言学习中我们都写过链表,栈和队列,我们总要实现Init和Destory函数并通过函数的调用来进行空间的开辟和回收,构造函数的出现显然省去了Init这一函数的调用,C++肯定不会只满足于这一点,与构造函数对应,析构函数应运而生
析构函数:与构造函数相反,析构函数并不是进行对象的销毁,对于局部对象,编译器在其生命周期结束时自动销毁,但是会先调用其析构函数,完成类的一些资源清理工作
2.2特性
特征如下:
1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值。(不能重载)
3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
对于对象的构造和析构也遵循压栈弹栈的顺序,先创建的在栈底,栈顶的先析构
4.1概念
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用
4.2特性
1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
3. 若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝
拷贝构造会对内置类型完成浅拷贝或者值拷贝,对自定义类型成员会调用它们自己的拷贝构造函数
我们发现由a1拷贝构造的a2指针对象data的地址相同,因而导致了析构时重复delete的错误,所以系统默认的拷贝构造函数只完成了浅拷贝
改用如下代码后程序正常运行
即赋值操作符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型或者枚举类型的操作数
用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义
作为类成员的重载函数时,其形参看起来比操作数啊目少1成员函数的操作符有一个默认的形参this,限定为第一个形参
.* 、:: 、sizeof 、?: 、. 以上5个运算符不能重载。必须要记住。
内置类型:语言层面就支持运算符
自定义类型:编译器默认不支持,c++可以用运算符重载让类对象支持用某个运算符
上述操作我们发现系统又报错了,说明编译器默认给的赋值函数为浅拷贝,
代码改写后运行正常
需要注意的地方:
1.引用传参 , 避免拷贝构造
2.引用返回,为了支持连续赋值操作
3.判断是否是自己给自己赋值,避免delete自己的成员后无法正确赋值
之前学习函数重载知道了const可以作为重载的区分条件,那么什么是const成员函数?
7.1概念
将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
7.2 使用
我们发现const A类型的a2调用show函数失败了,因为原先this的类型是A* const , 这就导致了参数类型不匹配,当我们加入const修饰的show后,const修饰的show的隐含this类型为const A* const ,这样程序再次正常运行
通过前面对于const成员函数的修饰,我们不禁会想为什么对于const对象取地址我们并没有重载对应的const函数但仍然取地址成功了呢?
这两个默认成员函数一般不用重新定义 ,编译器默认会生成