1、拷贝构造函数和赋值运算符
拷贝构造函数:用类的一个对象(的值)去构造另一个对象,后一个对象是不存在的,在拷贝构造的途中创建。
拷贝构造函数重载声明如下: A (const A&other)
A a;
A b(a);
A b=a; 都是拷贝构造函数来创建对象b
这里b对象是不存在的,是用a 对象来构造和初始化b的。
调用拷贝构造函数的三种场景:
- 一个对象以值传递的方式传给函数体
- 一个对象以值传递的方式从函数体返回
- 一个对象需要通过另一个对象初始化
赋值运算符:把类的一个对象(的值)赋值给类的另一个对象,两个对象都已经存在。
赋值运算的重载声明如下: A& operator = (const A& other)
A a;
A b;
b=a;
这里a,b对象是已经存在的,是用a 对象来赋值给b的。
2、深拷贝、浅拷贝
默认生成的拷贝构造函数是浅拷贝函数,不会处理内存释放等操作。只适用于int、string等数据类型。
存在的问题:如果定义了指针类型,但是没有自定义深拷贝函数,当用已有对象初始化另一个对象(调用浅拷贝函数)时,后一个对象的指针仅仅是指向了前一个对象指针指向的内存空间,当函数结束调用析构函数时,两个对象都会释放一次指针,导致内存泄漏。
深拷贝
使复制后的对象指针成员有自己的内存空间。
浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。
3、值传递、指针传递、引用传递
值传递:申请新的空间保存值,在函数内对形参进行更改时,不影响实参。形参的值、地址和实参的值、地址都没有关系。
指针传递:申请新的内存指针,让其指向实参的地址。用取值*改变形参值,就是对实参值进行改变。
引用传递:传递的是实参的地址,操作形参的值就是操作实参的值。
引用和指针传递的区别:
引用在创建时必须初始化,而且引用关系不可被改变;
在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
指针在创建时可以不初始化,而且在函数中可以改变其指向的内容。
指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)
引用是类型安全的,指针不是。