对象拷贝知识点

《c++ primer》13.1章节

《c++程序设计语言 第四版》17.5.1章节

1、拷贝操作有两种:

  • 拷贝构造函数:A(const A&)。初始化一片未经初始化的内存
  • 拷贝赋值运算符:A& operator=(const A&)。处理的目标对象已构造且可能拥有资源的情况

2、拷贝初始化:定义变量时拷贝其他对象的值来给对象初始化,在以下情况发生:

  • 用 = 定义变量时
  • 将对象作为实参传递给非引用类型的形参时
  • 从返回类型为非引用类型的函数返回对象时
  • 用{}列表初始化数组中的元素或聚合类中的元素时
  • 向容器中插入对象时(insert()和push()会拷贝对象)

3、拷贝构造函数必须使用引用的形式,原因是根据上面第2点,如果使用传值的方式,那么会触发拷贝初始化,即会调用拷贝构造函数,也就是当你要调用拷贝构造函数的时候的过程中会再次调用拷贝构造函数。这样无限套娃。

4、深拷贝和浅拷贝

深拷贝是指进行拷贝操作之后两个对象是相互独立的,浅拷贝相反,操作一个对象会改变另一个对象的状态:

#define debug qDebug()<<
class ceshi
{
public:
    ceshi(int * p = nullptr)
    {
        this->p = p;
    }
    ~ceshi()
    {
        if(p)
            delete p;
    }
    ceshi(const ceshi &c)
    {
        this->p = c.p;
    }
    void debugValue()
    {
        if(p)
            debug *p;
    }
    void changeValue(int value)
    {
        if(p)
            *p = std::move(value);
    }
private:
    int * p{nullptr};
};

int main(int argc, char *argv[])
{
    ceshi c1{new int(888)};
    ceshi c2{c1};
    c1.debugValue();
    c2.debugValue();

    c2.changeValue(444);
    c1.debugValue();
    c2.debugValue();
}

以上就是浅拷贝,拷贝时只拷贝指针的值,未拷贝指针指向的对象,当修改一个对象的状态时另一个的状态跟着变化。

这样的拷贝是深拷贝:

    ceshi(const ceshi &c)
    {
        if(c.p)
        {
            this->p = new int(*c.p);
        }
        else
        {
            this->p = nullptr;
        }
    }

5、写前拷贝

写前拷贝就是拷贝使用浅拷贝,当要修改的时候再进行复制资源的操作:

#define debug qDebug()<<
class ceshi
{
public:
    ceshi(int * p = nullptr)
    {
        this->p = p;
    }
    ~ceshi()
    {
        if(p)
            delete p;
    }
    ceshi(const ceshi &c)
    {
        this->p = c.p;
        isShare = true;
    }
    void debugValue()
    {
        if(p)
            debug *p;
    }
    void changeValue(int value)
    {
        if(isShare)
        {
            clone();
            isShare = false;
        }

        if(p)
        {
            *p = std::move(value);
        }
    }
private:
    int * p{nullptr};
    bool isShare;//是否正在和其他对象共享资源
    void clone()
    {
        if(isShare)
        {
            if(p)
            {
                p = new int(*p);
            }
        }
    }
};

int main(int argc, char *argv[])
{
    ceshi c1{new int(888)};
    ceshi c2{c1};
    c1.debugValue();
    c2.debugValue();

    c2.changeValue(444);
    c1.debugValue();
    c2.debugValue();
}

这里增加一个变量isShare,标识当前对象是否在和其他对象共享资源,拷贝后设为true,当改变值时调用clone()函数复制资源。

6、拷贝与切片

#define debug qDebug()<<
class A
{
public:
    A(int a = 444)
    {
        this->a = a;
    }
    A(const A & obj)
    {
        this->a = obj.a;
        debug "调用A拷贝";
    }
private:
    int a;
};

class B : public A
{
public:
    B(int b = 555)
    {
        this->b = b;
    }
    B(const B & obj)
    {
        this->b = obj.b;
    }
private:
    int b;
};

int main(int argc, char *argv[])
{
    B objB{888};
    A objA = objB;
}

这里基类对象等于子类对象会调用基类的拷贝构造函数,得到的结果是一个基类对象,导致子类中的成员b丢失。这种现象操作切片,要禁止这类操作可以:

  • 禁止基类拷贝:A(const A & obj) = delete;
  • 不使用共有继承:class B : public A,改成private或protected
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值