拷贝构造函数和赋值函数

本文主要是对拷贝构造函数和赋值函数已经深拷贝、浅拷贝的总结归纳。

拷贝构造函数

如果构造函数第一个参数为自身类类型的引用,且任何额外参数都具有默认值,则此构造函数为拷贝构造函数。

class Foo
{
public:
    Foo();              //默认构造函数
    Foo(const Foo&)     //拷贝构造函数
};

拷贝构造函数的第一个参数必须为一个引用。默认情况下如果没有显式定义拷贝构造函数,编译器将生成默认拷贝构造函数,这一点和构造函数相似。

我们可以使用delete删除拷贝构造函数。这样对象不能通过值传递,也不能进行赋值。需要注意析构函数不能够使用delete删除

class Person
{
public:

    Person(const Person& p) = delete;

    Person& operator=(const Person& p) = delete;

private:
    int age;
    string name;
};

拷贝构造函数的调用场景:

  • 将一个对象作为函数参数
  • 函数返回值为一个非引用型对象
  • 使用一个对象初始化另一个对象。

拷贝构造函数与赋值函数

相似之处都是将一个对象给另一个对象赋值,区别在于拷贝构造函数是将对象赋值给一个新的实例,而赋值函数是赋值给一个已存在的实例。

可以结合下面代码理解。

代码如下:

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;    // 1
    Person p2;
    p2 = p;           // 2
    f(p2);            // 3
    p2 = f1();        // 4
    Person p3 = f1(); // 5
    return 0;
}

对于第5个暂时有点懵。。按照上面规则分析,应该是会调用拷贝构造函数。但是只出现了四个结果,而且都是对应前四个编号。利用gcc编译器测试发现将对象作为函数值返回并没有调用拷贝构造函数。

深拷贝浅拷贝

浅拷贝

对于没有显式声明拷贝构造函数的类,编译器会生成一个默认拷贝构造函数,这个默认拷贝构造函数会对拷贝对象进行简单拷贝。在大多数情况下这样问题不大,当存在动态变量(例如指针)时。这就是浅拷贝的问题。

看下面一段代码

class Rect  
{  
public:  
    Rect()      // 构造函数,p指向堆中分配的一空间  
    {  
        p = new int(100);  
    }  
    ~Rect()     // 析构函数,释放动态分配的空间  
    {  
        if(p != NULL)     
        {  
            delete p;  
        }  
    }  
private:  
    int width;  
    int height;  
    int *p;     // 一指针成员  
};  

int main()  
{  
    Rect rect1;  
    Rect rect2(rect1);   // 复制对象  
    return 0;  
}  

在析构的时候会出现问题,因为并没有为rect2的指针,单独分配空间,但是析构的时候却删除了两遍,所以会出现问题。并且如果你期中一个对象的值改变了,另外一个对象的值也随着一起改变。

如下图所示。

深拷贝

需要单独为动态成员分配空间,因此需要将复制构造函数改为

Rect(const Rect &r)
{
    width=r.width;
    height = r.height;
    p= new int[100]
}

为每一个动态变量单独分配空间

总结

  • 拷贝构造函数和赋值运算符的行为比较相似,却产生不同的结果;拷贝构造函数使用已有的对象创建一个新的对象,赋值运算符是将一个对象的值复制给另一个已存在的对象。区分是调用拷贝构造函数还是赋值运算符,主要是否有新的对象产生。

  • 关于深拷贝和浅拷贝。当类有指针成员或有动态分配空间,都应实现自定义的拷贝构造函数。提供了拷贝构造函数,最后也实现赋值运算符。-

猜你喜欢

转载自blog.csdn.net/gzj_1101/article/details/80521603