1、拷贝构造函数:用一个已经有的对象构造一个新的对象。

CAconst CA & c )函数的名称必须和类名称相一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const 类型,不可变。

   拷贝构造函数什么时候被用到?

(1)当用一个已初始化过的自定义类型对象去初始化另一个新构造的对象的时候。

(2)一个对象以值传递的方式传入。在调用函数时需要将实参对象完整的传递给形参,系统是通过调用拷贝构造函数来实现的,这样能保证形具有和实参完全相同的值。

(3)一个对象以值传递的方式传出函数体。在函数调用完毕将返回值带回函数调用处。此时需要将函数中的对象拷贝到一个临时对象处并传给该函数的调用处。

 拷贝构造函数为什么传引用而不传值?

如果拷贝构造函数进行值传递的话,那么形参会产生一个新对象,也就是会调用拷贝构造函数,因此会形成一个死循环。

调用拷贝构造函数需要先创建形参对象,创建形参对象又需要调用拷贝构造函数,无限递归肯定是不正确的,所以在这里要用引用而不是值传递。

 

2、赋值运算符的重载函数:用一个已经有的对象给一个同一类型的对象赋值。(两个对象都存在)

CA & operator = (const  CA & )

返回值的对象为引用是为了可以连续赋值

赋值函数中可以既可以使用引用也可以使用值传递,不过值传递会多生成一个对象,造成资源的浪费。

class A
{
private:
 int a;
 int b;
public:
 A (const A & arg) // 拷贝构造函数  
 {
  a = arg.a;
  b = arg.b;
 }
 A & operator = ( const A & arg) //重载的赋值函数 
 {
  if(this != &arg)// 先判断下是否是自身赋值
  {
   a = arg.a;
   b = arg.b;
  }
  return *this;
 }
};

当类中含有指针成员时,两者的意义有很大区别

复制构造函数需为指针变量分配内存空间,并将实参的值拷贝到其中;而赋值操作符它实现的功能仅仅是将‘=’号右边的值拷贝至左值,在左边对象内存不足时,

先释放然后再申请。当然赋值操作符必须检测是否是自身赋值,若是则直接返回当前对象的引用而不进行赋值操作。

拷贝构造函数分为两类:

一类是系统默认提供的拷贝构造函数,只是简单的把栈里面的数据进行拷贝,堆上面的内容没有进行拷贝。
二类是自己定义的拷贝构造函数,能够对堆上面的东西进行深度的拷贝。
 
这里又要提到深拷贝和浅拷贝的问题。
 
浅拷贝

深拷贝

class Student
{
private:
 char *name;
public:
 Student (const Student & arg)
 {
  int length = strlen(arg.name)+1;
  this->name = new char[length];   // 深拷贝,先在堆上分配内存,再拷贝内容。
  strncpy(this->name,arg.name,length);
 }
 Student & operator=( const Student &arg)
 {
  if(this != &arg)
  {
   delete []name;// 先销毁之前分配的堆上的内存
  }
  int length = strlen(arg.name)+1;
  this->name = new char[length];// 重新分配,并拷贝。
  strncpy(this->name,arg.name,length);
  return *this;
 }
};