类的六个默认的成员函数
类的6个默认的成员函数包括:
构造函数、析构函数、拷贝构造函数、赋值运算符重载函数、取地址操作符重载、const修饰的取地址操作符重载。
(一)构造函数
构造函数,顾名思义,为对象分配空间,进行初始化。它是一种特殊的成员函数,具有以下特点:
函数名与类名相同。
无返回值。
构造对象的时候系统会自动调用构造函数。
可以重载。
可以在类中定义,也可以在类外定义。
如果类中没有给出构造函数,编译器会自动产生一个缺省的构造函数,如果类中有构造函数,编译器就不会产生缺省构造函数。
全缺省的构造函数和无参的构造函数只能有一个,否则调用的时候就会产生冲突。
没有this指针。因为构造函数才是创建对象的,没有创建对象就不会有对象的首地址。
构造函数,说来就是给成员变量进行初始化。而初始化却有两种方法:初始化列表、构造函数函数体内赋值。尽量使用初始化列表,因为它更高效。
有些成员变量必须再初始化列表中初始化,比如:
常量成员变量。(常量创建时必须初始化,因为对于一个常量,我们给它赋值,是不对的)
引用类型成员变量。(引用创建时必须初始化)
没有缺省构造函数的类成员变量。(如果构造函数的参数列表中有一个类的对象,并且该对象的类里没有缺省参数的构造函数时,要是不使用初始化列表,参数中会调用无参或者全缺省的构造函数,而那个类中又没有。)
(二)析构函数
析构函数是一种特殊的成员函数,具有以下特点:
析构函数函数名是在类名加上字符 ~ 。
无参数无返回值(但有this指针)。
一个类有且只有一个析构函数,所以肯定不能重载。若未显示定义,系统会自动生成缺省的析构函数。
对象生命周期结束时,C++编译系统系统自动调用析构函数。
注意析构函数体内并不是删除对象,而是做一些清理工作。(比如我们在构造函数中动态开辟过一段空间,函数结束后需要释放,而系统自动生成的析构函数才不管内存释放呢,所以需要人为地写出析构函数)
注意:对象生命周期结束后,后构造的对象先释放。
(三)拷贝构造函数
用已有的对象创建一个新的对象。
创建对象时使用同类对象来进行初始化,这时所用的构造函数就是拷贝构造函数(Copy Constructor)。拷贝构造函数也是构造函数,但它只有一个参数,这个参数只能是本类的一个对象,而且采用对象的常引用形式。拷贝构造函数的作用就是将实参对象的各成员值一一赋给新的对象中对应的成员。
该函数的参数是一个常引用,如果不是引用,形参是实参的一份临时拷贝,由于两者都是对象,此时就会调用自己的拷贝构造函数,陷入无限递归中…….
拷贝构造函数的特征
(1)拷贝构造函数其实是一个构造函数的重载。
(2)拷贝构造函数的参数必须使用引用传参,使用传参方式会引发无穷递归调用。
(3)若为显示定义,系统默认生成缺省的拷贝构造函数,缺省的拷贝构造函数会按照成员的声明顺序依次拷贝类成员进行初始化
调用拷贝构造函数的两种方法:
代入法:
Person p2(p1);
赋值法:
Person p2 = p1;
为什么这里的对象可以直接访问私有成员变量?
1)在类的成员函数里可以直接访问同类对象的私有或保护的成员。
2)C++的访问限定符是以类为单位的,即:在这个单位内的成员可以互相访问。
(四)赋值运算符重载函数
用一个对象修改已经存在对象的内容,不是去创建新的对象,修改之后,两个对象的内容一致
- 可以通过检查是否给自己赋值,进行优化
- 如果需要连续赋值,返回值不能是void,一般为引用类型
- *返回值一般是 this
- 编译器默认生成的赋值运算符为字节拷贝,即浅拷贝,如果资源需要拷贝,需要显示定义,完成深拷贝
=调用:如果对象都存在,调用赋值运算符重载函数
如果左边对象不存在,调用拷贝构造创建左边对象
赋值是从右向左进行的
如果不写,编译器会自动生成,默认生成的也是字节拷贝,浅拷贝
如果当前类中有资源,则必须显示定义运算符重载函数,完成深拷贝
普通运算符重载函数
- 不能创建新的操作符,如operator@
- 重载操作符必须有一个类类型或者枚举类型的操作符
- 用于内置类型的操作符,其含义不能改变
- 运算符重载函数如果是成员函数,则参数的个数比运算符需要的个数少一个,这里编译器会传入this指针作为第一个参数
- 普通的运算符重载函数,参数的个数和运算符需要的个数一致
.*(成员指针访问运算符) , :: , sizeof , ? : , . 五个运算符不能被重载
(五)取地址运算符重载函数 / const取地址运算符重载函数:获取对象的地址**
一般不需要显示定义,直接使用编译器自动生成的即可