在 c++ 中经常需要开发人员手动实现类的拷贝构造函数和赋值操作符。一般来说,如果类中的字段是基本类型,则拷贝构造函数和赋值操作符不需要开发人员手动实现,可以直接使用系统默认。如果类中的字段是指针、非基本类型,为了保证不出现两个变量指向同一个对象的,情况,需要手动重写两个方法。因为存在指针变量,子类继承等多种情况,所以从变量、父类、子类依次实现。
数据类 Object_data,在父类 Base_class 中以指针变量出现。
Object_data 继承 QObject,有两个基本类型字段。
#ifndef OBJECT_DATA_H
#define OBJECT_DATA_H
#include
/**************************************************************************************************
@Copyright 2008-2022
@Date 2022-06-28
@Author qiaowei
@Contact [email protected]
@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 [email protected]
@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 [email protected]
@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
class Object_data;
/**************************************************************************************************
@Copyright 2008-2022
@Date 2022-06-28
@Author qiaowei
@Contact [email protected]
@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
#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;