复制构造函数

假设定义了一个ClassDemo的类

class ClassDemo
{
public:
    ClassDemo();
    ClassDemo(int num);
    ~ClassDemo();
private:
    int _num;
};

在main函数中

CLassDemo demo = 10;
demo = 20;

第一句话代表的并不是赋值,此时会调用转换构造函数。
第二句话会调用默认的赋值函数:先通过转换构造函数创建一个临时的对象,再将该对象传递给默认的赋值函数,最后析构该临时对象。
请参考构造函数讲解

如果在main函数中

ClassDemo demo = 10;
ClassDemo demo1 = demo;

第二句话并非一个赋值,此时它会调用复制构造函数。

这是复制构造函数的函数原型,它会将类中的所有成员变量复制到对象中

ClassDemo(const ClassDemo &other);

复制构造函数的形参必须是一个引用,否则编译是无法通过的。如果形参不是一个引用的话,此时会产生无限递归,因为将一个对象传递到复制构造函数中时,此时会为该对象产生一个副本,而产生副本的过程就会调用复制构造函数,此时便产生了无限递归。

举个例子:
void f1(ClassDemo demo)
{
}

void f2(ClassDemo &demo)
{
}
在main函数调用这两个函数产生的结果是不一样的

ClassDemo demo;
f1(demo);
f2(demo);

程序在执行到f1的时候,因为f1的形参为类的对象。此时首先会调用复制构造函数创建这个对象。然后才会进入f1函数执行函数体的部分。在f1执行完之后该对象会被析构。
程序执行到f2的时候,因为传递的是一个对象的引用,此时不会有新的对象产生,复制构造函数不会执行,此时会直接执行f2函数体部分,也不会有析构函数的调用。

学到这里可以知道,在一个空类中有4个函数会被默认生成。
默认构造函数
默认析构函数
默认复制构造函数
默认赋值函

关于复制构造函数的使用:

class MyString
{
pubilc:
    MyString(char *str):_len(strlen(str))
    {
        new char[_len + sizeof(char)];
        strcpy(_str, str);
    }
    ~MyString()
    {
        if(_str)
            delete[]_str;
    }
    MyString(MyString &other)
    {
        _str = other._str;
    }
    MyString& operator=(MySting &other)
    {
        _len = other._len;
        _str = other._str;
        return *this;
    }
    char *GetString()
    {
        return _str;
    }
private:
    char *_str;
};
int main()
{
    MyString demo = "I Have Apple";
    MyString demo1 = demo;
    std::cout << demo1.GetString();
    demo1 = "I Have Pen";
    std::cout << demo1.GetStrinf();
    return 0;
}

打印的结果为:
这里写图片描述

这是因为在执行demo1 = “I Have Pen”的时候会调用默认的赋值函数。
默认的赋值函数首先会创建一个临时的对象temp
然后会将该临时对象的值给demo1
即为:

MyString operator=(const MyString& temp)
{
    _str = temp._str;
    _len = temp._len;
}

在该赋值函数结束后,临时对象temp会被析构掉。所以指向temp._str的空间会被delete。此时的demo1. _str所指向的空间被delete了,demo1. _str也就变成了野指针,所以打印出来的结果自然也是未知的。在vs编译器的dubug下这段空间会被填充成0xdddddddd。

所以当我们类的成员变量中存在指针的时候,使用默认的复制构造函数和默认的赋值函数时就会存在风险

这种直接对指针的赋值称为浅拷贝。使得指针易被delete,在这种情况下应当使用深拷贝来维护该成员变量的生命周期。

MyString(MyString &other)
{
    delete[]_str;
    _len = other._len;
    _str = new char[_len + sizeof(char)];
    strcpy(_str, other._str);
}
MyString& operator=(MySting &other)
{
    delete[]_str;
    _len = other._len;
    _str = new char[_len + sizeof(char)];
    strcpy(_str, other._str);
    return *this;
}

深拷贝实质上是维护了对象中所有属性的生命周期。使其生命周期和对象是同步的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值