C++ 浅拷贝与深拷贝

在 c++ 中经常需要开发人员手动实现类的拷贝构造函数和赋值操作符。一般来说,如果类中的字段是基本类型,则拷贝构造函数和赋值操作符不需要开发人员手动实现,可以直接使用系统默认。如果类中的字段是指针、非基本类型,为了保证不出现两个变量指向同一个对象的,情况,需要手动重写两个方法。因为存在指针变量,子类继承等多种情况,所以从变量、父类、子类依次实现。

数据类 Object_data,在父类 Base_class 中以指针变量出现。

Object_data 继承 QObject,有两个基本类型字段。

#ifndef OBJECT_DATA_H
#define OBJECT_DATA_H

#include <QObject>

/**************************************************************************************************
  @Copyright  2008-2022
  @Date       2022-06-28
  @Author     qiaowei
  @Contact    weiweiqiao@126.com
  @Version    1.0
  @Brief      测试类。继承QObject,重写拷贝构造函数,赋值操作符。
  @Other      None
  @History    None
  @Method     None
  @Fields     None
**************************************************************************************************/
class Object_data : public QObject
{
    Q_OBJECT

public:
    explicit Object_data(int num01, int num02, QObject *parent = nullptr);

    /**********************************************************************************************
     @date     2022-06-28
     @author   qiao wei
     @contact  weiweiqiao@126.com
     @version  1.0
     @other    Used/Unused
     @brief    拷贝构造函数。
     @param    None
     @return   None
    **********************************************************************************************/
    explicit Object_data(const Object_data& value);

    virtual ~Object_data();

    /**********************************************************************************************
     @date     2022-06-28
     @author   qiao wei
     @contact  weiweiqiao@126.com
     @version  1.0
     @other    Used/Unused
     @brief    赋值操作符。
     @param    None
     @return   None
    **********************************************************************************************/
    Object_data& operator= (const Object_data& value);

    int num01_;
    int num02_;
};

#endif // OBJECT_DATA_H

1:拷贝构造函数中要对基类 QObject 和字段分别处理,注意先后顺序;赋值操作符先对两者是否同一对象进行判断,然后进行赋值。

#include "object_data.h"

Object_data::Object_data(int num01, int num02, QObject *parent)
    : QObject{parent}
    , num01_{num01}
    , num02_{num02}
{
}

Object_data::Object_data(const Object_data &value)
    : QObject{nullptr}
    , num01_{value.num01_}
    , num02_{value.num02_}
{
    // 功能同初始化字段
//    if (this != &value) {
//        num01_ = value.num01_;
//        num02_ = value.num02_;
    //    }
}

Object_data::~Object_data()
{

}

Object_data &Object_data::operator=(const Object_data &value)
{
    if (this != &value) {
        num01_ = value.num01_;
        num02_ = value.num02_;
    }

    return *this;
}

父类

Object_data * 作为数据出现

#ifndef BASE_CLASS_H
#define BASE_CLASS_H

#include <QObject>

class Object_data;

/**************************************************************************************************
  @Copyright  2008-2022
  @Date       2022-06-28
  @Author     qiaowei
  @Contact    weiweiqiao@126.com
  @Version    1.0
  @Brief      父类,继承自QObject。
  @Other      None
  @History    None
  @Method     None
  @Fields     None
**************************************************************************************************/
class Base_class : public QObject
{
    Q_OBJECT
public:
    explicit Base_class(QObject* parent = nullptr);

    explicit Base_class(int num01, int num02, QObject *parent = nullptr);

    explicit Base_class(const Base_class& value);

    virtual ~Base_class();

    Base_class& operator= (const Base_class& value);

    Object_data* object_data_;
};

#endif // BASE_CLASS_H

因为在构造函数中对 object_data_变量进行初始化 new,所以在拷贝构造函数中要先判断是否与传入的数据指向同一地址,如果不一样,delete object_data_的现有数据,再进行 new 赋值,避免造成内存泄漏。赋值操作符、析构函数中进行比较是同样的意思。

#include "base_class.h"
#include "object_data.h"

Base_class::Base_class(QObject *parent)
    : QObject{parent}
    , object_data_{new Object_data{0, 0, parent}}
{
}

Base_class::Base_class(int num01, int num02, QObject *parent)
    : QObject{parent}
    , object_data_{new Object_data{num01, num02, parent}}
{
}

Base_class::Base_class(const Base_class &value)
    : QObject(nullptr)
{
    if (this != &value) {
        delete object_data_;

        // 非基础类型数据赋值,避免不同指针指向同一对象。如果存在非基础类型数据,需要手动赋值。
        object_data_ =
                new Object_data(value.object_data_->num01_,
                                value.object_data_->num02_,
                                nullptr);
    }
}

Base_class::~Base_class()
{
    if (nullptr != object_data_) {
        delete object_data_;
        object_data_ = nullptr;
    }

    QObject::~QObject();
}

Base_class &Base_class::operator=(const Base_class &value)
{
    if (this != &value) {
        delete object_data_;

        // 非基础类型数据赋值,避免不同指针指向同一对象。如果存在非基础类型数据,需要手动赋值。
        object_data_ =
                new Object_data(value.object_data_->num01_,
                                value.object_data_->num02_,
                                nullptr);
    }

    return *this;
}

子类:

#ifndef DEPRIVED_CLASS_H
#define DEPRIVED_CLASS_H

#include <QObject>
#include "base_class.h"

class Deprived_class : public Base_class
{
    Q_OBJECT
public:
    explicit Deprived_class(QObject *parent = nullptr);

    explicit Deprived_class(int num01, int num02, QObject* parent = nullptr);

    explicit Deprived_class(const Deprived_class& value);

    virtual ~Deprived_class();

    Deprived_class& operator= (const Deprived_class& value);

    int index_;
};

#endif // DEPRIVED_CLASS_H

注意拷贝构造函数中父类拷贝构造函数的调用;父类赋值操作符的调用。

#include "deprived_class.h"

Deprived_class::Deprived_class(QObject *parent)
    : Base_class{parent}
{

}

Deprived_class::Deprived_class(int num01, int num02, QObject *parent)
    : Base_class{num01, num02, parent}
    , index_(num01 - num02)
{

}

Deprived_class::Deprived_class(const Deprived_class &value)
    : Base_class(value)
{
    if (this != &value) {
        index_ = value.index_;
    }
}

Deprived_class::~Deprived_class()
{
    Base_class::~Base_class();
}

Deprived_class &Deprived_class::operator=(const Deprived_class &value)
{
    if (this != &value) {
        // 调用Base_class类的赋值操作符,将基类中字段进行赋值操作。
        Base_class::operator=(value);

        // 将Deprived_class类中的字段进行赋值。
        index_ = value.index_;
    }

    return *this;
}

结果:

Deprived_class* d01{new Deprived_class{10, 20, nullptr}};
    qDebug()<< d01->index_ << Qt::endl;
    qDebug()<< d01->object_data_->num02_ << Qt::endl;

    Deprived_class* d02{new Deprived_class{5, 4000, nullptr}};
    *d02 = *d01;
    qDebug()<< d02->index_ << Qt::endl;
    qDebug()<< d02->object_data_->num02_ << Qt::endl;

    d02->object_data_->num02_ = 200;
    qDebug()<< d01->object_data_->num02_ << Qt::endl;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值