把参数传递给函数有三种方法,一种是传值,一种是传地址,一种是传引用。传值与其余两种方式不一样的地方在于 当使用函数
传值方式的时候,会在函数里面生成传递参数的一个副本,这个副本的内容是按位从原始参数那里复制过来的,二者的内容是相同的。spa
当原始参数是一个类的对象时,它也会产生一个对象的副本,此时须要注意:通常对象在建立时都会调用构造函数来进行初始化,可是指针
在产生对象的副本时若是再执行对象的构造函数,那么这个对象的属性又再恢复到原始状态,这就不是咱们但愿的了。因此在产生对象对象
副本的时候,构造函数不会被执行,被执行的是一个默认的默认的拷贝构造函数。内存
问题缘由: 编译器
当函数执行完毕要返回的时候对象副本会执行析构函数,编译
若是你的析构函数是空的话,也不会发生什么问题,但通常的析构函数都是要完成一些清理工做,如释放指针所指向的内存空间,这时候变量
可能就会出问题。 譬如:咱们在构造函数中为一个指针变量分配了内存,在析构函数中释放给这个指针所指向的内存空间,在把对象传递循环
给函数至函数结束返回 的这个过程当中 首先有一个对象的副本产生了。这个副本也有一个指针,它和原始对象的指针是指向同块内存空间的,构造函数
函数返回时,副本对象的析构函数执行了,释放了副本对象中指针指向的内存空间,可是这个内存空间对于原始对象而言仍是有效地,
这是第一个问题,后面当原始对象也被销毁的时候,原始对象的析构函数执行,还会对那块已经释放掉的内存空间再次释放,产生严重
错误,这是第二个问题。
解决方法:
既然传值有这样的问题,那是否可使用传地址或者传引用的方式解决这种问题呢?
事实上传地址和传引用确实能够解决这种问题,可是这并不适用全部的状况,有时咱们不但愿在函数里面的一些操做会影响到函数外部的变量。
为了解决这种问题,此时就须要用到拷贝构造函数,拷贝构造函数就是在产生副本对象的时候执行的,在拷贝构造函数里面咱们申请一个新的内存空间,
这样在副本对象执行析构函数时其释放的就是新的内存空间,从而解决这个问题。
适用范围:
1. 一个对象以值传递的方式传入函数体
2. 一个对象以值传递的方式从函数返回
3. 一个对象须要经过另一个对象进行初始化
拷贝构造函数不能够改变它所引用的对象,若是能够改变,那么将致使无限循环,若是类中没有显示的声明一个拷贝构造函数,
那么编译器会为你隐式定义一个位拷贝的默认拷贝构造函数
若是不许备使用按值传递对象,那么实际上是不须要拷贝构造函数,可是咱们若是不写拷贝构造函数,编译器又可能为咱们建立一个默认的。
那么如何保证一个对象将永远不会被经过按值传递方式传递呢?
声明一个私有的拷贝构造函数,甚至没必要去定义它,除非成员函数或友元函数须要执行按值传递方式的传递。不然,若是用户试图用按值传递方式传递
或返回对象,编译器将会报错。这是由于拷贝构造函数是私有的。由于已经显示地声明咱们接管了这项工做,因此编译器再也不建立默认的拷贝构造函数