天天看点

C++ 拷贝构造函数和重载赋值运算符的区别

文章目录

  • ​​拷贝构造函数​​
  • ​​重载赋值运算符​​

赋值运算符和拷贝构造函数最大区别是赋值运算符没有新的对象生成,而拷贝构造函数会生成新的对象。

为了更加形象 准确得描述 赋值运算符和拷贝构造函数得区别,将详细通过代码展示两者之间得差异。

拷贝构造函数

首先从构造函数说起,在C++面向对象的设计中,每一个对象代表一个抽象集合的实体,此时每一个实体在当前运行的进程中是需要对应的内存空间,即对象存在则有空间。为此,C++引入构造函数来实例化对象,并让编译器为该对象向操作系统申请对应的空间,从而能够存在于操作系统之中。

拷贝构造函数则是为了将老对象的数据成员一一赋值给新的对象数据成员的一种构造函数,即拷贝构造函数的结果和构造函数一致,都是有新的对象生成。

查看如下代码:

#include <iostream>
using namespace std;

class A{
public:
    A(){ cout << "default constructor " << endl;  }
    A(int a) {num=a;cout << "constructor with param" << endl; }
    A(const A &a)
    {
        num=a.num;
        cout << "copy constructor " << endl;
    }
    ~A(){ cout << "destructor " << this->num << endl; }
    void print()
    {
        cout << this->num << endl;
    }

private:
    int num;

};
void para_copy(A &a)
{
}
int main()
{
    A a(100); // 重载构造函数
    A a1=a; //拷贝构造函数
    a1.print();
    A c;//默认构造函数
    return 0;
}      

输出如下:

constructor with param //a 重载构造
copy constructor //a1 拷贝构造
100
default constructor //c默认构造
destructor 0 //c析构
destructor 100 //a1析构
destructor 100 //a析构      

拷贝构造函数调用场景如下:

  • 我们如上代码中 一个对象由另一个对象来初始化
  • 对象作为函数参数
  • 对象作为函数返回值

    关于对象作为函数参数以及返回值时调用的拷贝构造函数,查看代码如下

#include <iostream>
using namespace std;

class A{
public:
    A(){ cout << "default constructor " << endl;  }
    A(int a) {num=a;cout << "constructor with param" << endl; }
    A(const A &a)
    {
        num=a.num;
        cout << "copy constructor " << endl;
    }
    ~A(){ cout << "destructor " << this->num << endl; }
    void print()
    {
        cout << this->num << endl;
    }

private:
    int num;

};
void param_copy(A a)
{
    cout << "param obj" << endl;
}
A return_value()
{
    A d(0);
    cout << "return obj" << endl;
    return d;
}
int main()
{
    A c;
    param_copy(c);
    return_value();
    return 0;
}      
  • 输出如下
default constructor  //c 默认构造
copy constructor // 对象做参数,拷贝构造到临时对象
param obj
destructor 0 // 析构掉临时对象
constructor with param //函数return_value中 d 对象使用了重载构造函数
return obj 
destructor 0 //析构掉 d对象 ,局部变量
destructor 0 //析构掉 c对象      

关于深拷贝和浅拷贝的描述如下:

  1. 通常,默认生成的拷贝构造函数和赋值运算符,只是简单的进行值的复制。如果类的数据成员有指针,仅仅通过值传递进行拷贝构造的话会造成两个对象的成员指针指向同一块内存,当两个对象析构的时候会对同一个内存释放两次,从而会造成指针空悬。
  2. 深拷贝即以上第二种情况,数据成员中有指针变量的时候拷贝构造函数使用深拷贝,即构造函数中重新指定初始化对象的地址空间。

    代码如下:

#include <iostream>
using namespace std;

class A{
public:
    A(){ p=new int(10);cout << "default constructor " << endl;  }
    //A(int a) {num=a;cout << "constructor with param" << endl; }
    A(const A &a)
    {
        num=a.num;
        p=new int(10);
        *p=*(a.p);
        cout << "copy constructor " << endl;
    }
    ~A(){ cout << "destructor " << this->num << endl; }
    void print()
    {
        if(p!=NULL)
        {
          delete p;
          cout << this->num << endl;
        }
    }

private:
    int num;
    int *p;

};
void param_copy(A a)
{
    cout << "param obj" << endl;
}
int main()
{
    A c;
    A b(c);
    return 0;
}      

重载赋值运算符

#include <iostream>
using namespace std;

class Person
{
public:
    Person(){}
    Person(const Person& p)
    {
        cout << "Copy Constructor" << endl;
    }
 
    Person& operator=(const Person& p)
    {
        cout << "Assign" << endl;
        return *this;
    }
 
private:
    int age;
    string name;
};
 
void f(Person p)
{
    return;
}
 
Person f1()
{
    Person p;
    return p;
}
 
int main()
{
    Person p;
    Person p1 = p;    // A
    cout <<" p1 addr " <<  &p1 << endl;
    Person p2;
    cout <<" p2 addr " <<  &p2 << endl;
    p2 = p;           // B
    cout <<" p2 addr after asign " <<  &p2 << endl;
    f(p2);            // C f函数参数
    cout <<" p2 addr after asign " <<  &p2 << endl;
 
    p2 = f1();        // D f1返回值为改对象,则先进行拷贝构造,在将返回的对象赋值给p2
    cout <<" p2 addr after asign " <<  &p2 << endl;
 
    Person p3 = f1(); // E 生成新对象,则为拷贝构造函数
    cout <<" p3 addr " <<  &p3 << endl;
 
    getchar();
    return 0;
}      
Copy Constructor
Assign
Copy Constructor
Copy Constructor
Assign
Copy Constructor      

继续阅读