赋值操作符(Copy constructor Assignment operator)"/>
C++中拷贝构造函数和赋值操作符(Copy constructor Assignment operator)
在C++中,经常会将对象进行赋值或拷贝,在C++中,在程序员没有手动编写相关内容时,系统会自动创建拷贝构造函数和复制操作符内容,对于值类型数据使用系统默认的函数可以正常运行,但是对于类类型、指针类型,系统自动自动创建的操作函数无法将类类型、指针类型创建副本,而是两个类对象同时持有一个拷贝副本,改变一个类对象数据,会造成另个一类对象数据改变,造成隐性bug。
在编写拷贝构造函数和赋值操作符时注意事项:
- 首先调用基类的构造函数或赋值操作符,对基类数据进行拷贝。
- 拷贝构造方法是构造方法的一种,初始化变量,所以不需要对指针类型字段进行空指针判别。
- 对当前类的字段按照在“.h”文件中声明的顺序进行赋值,所有字段都要赋值。
- 赋值操作符对指针类型字段先进行空指针判别,进行delete后再进行赋值,预防内存泄漏问题。
数据类:
.h
#ifndef DATA_CLASS_H
#define DATA_CLASS_H#include <QObject>/*** @copyright 2008-2023* @date 2023-07-14* @author qiaowei* @version 1.0* @brief 数据类。有2个变量,分别是QString,int类型。* @history None* @function None* @field None
*/
class DataClass : public QObject
{Q_OBJECTpublic:explicit DataClass(QObject *parent = nullptr);/*** @author qiao wei* @version 1.0* @brief Copy constructor.* @param value 拷贝的变量。* @return None*/DataClass(DataClass& value);virtual ~DataClass();DataClass& operator =(const DataClass& value);public:QString name_;int level_;
};#endif // DATA_CLASS_H
.cpp
#include <QtDebug>#include "data-class.h"DataClass::DataClass(QObject *parent): QObject{parent}, name_{""}, level_{0}
{}DataClass::DataClass(DataClass& value)
{// QObject's copy constructor and assignment operator are declared in a private section.if ((nullptr != &value) && (this != &value)) {this->name_ = value.name_;this->level_ = value.level_;}
}DataClass::~DataClass()
{}DataClass &DataClass::operator =(const DataClass &value)
{// QObject's copy constructor and assignment operator are declared in a private section.if (this == &value) {return *this;}// 赋值操作符要对指针字段先进行delete,使用nullprt赋值。保证不会出现内存泄漏。this->name_ = value.name_;this->level_ = value.level_;return *this;
}
类中的两个字段分别为QString、int类型。作为基础类型,也可以不用重写拷贝构造函数和赋值操作符。
父类BaseClass有2个字段,分别是DataClass指针data_,QString类型local_,因为字段data_为类指针,所有BaseClass必须重写拷贝构造函数和赋值操作符。
注意事项:
- 拷贝构造函数是构造函数的一种,不需要对指针字段进行判断,不需要delete避免内存泄漏情况。
- 赋值操作符是对已经创建的两个字段进行赋值,因为两个变量都已经new过,只是其中字段的赋值,所以要对指针字段进行判断,需要delete已经new的指针字段,避免内存泄漏情况。
- 注意拷贝构造函数,赋值操作符中的字段处理顺序。建议按照构造函数中的字段处理顺序,先基类,后字段,字段按照类声明的顺序赋值。
.h文件:
#ifndef BASECLASS_H
#define BASECLASS_H#include <QObject>#include "data-class.h"/*** @copyright 2008-2023* @date 2023-07-07* @author qiaowei* @version 1.0* @brief None* @history None* @function None* @field None
*/
class BaseClass : public QObject
{Q_OBJECTpublic:/*** @author qiao wei* @contact weiweiqiao@126* @version 1.0* @other Used/Unused* @brief Constructor。构造方法不能调用virtual方法。* @param None* @return None*/explicit BaseClass(QObject *parent = nullptr);/*** @author qiao wei* @contact weiweiqiao@126* @version 1.0* @other Used/Unused* @brief Copy constructor。需要调用拷贝构造方法时不会调用其它的构造方法。同构造方法不能调用* virtual方法。* @param value 要拷贝的变量。* @return None*/BaseClass(const BaseClass& value);/*** @author qiao wei* @contact weiweiqiao@126* @version 1.0* @other Used/Unused* @brief Destructor.* @param None* @return None*/virtual ~BaseClass();/*** @author qiao wei* @contact weiweiqiao@126* @version 1.0* @other Used/Unused* @brief Assignment Operator.* @param value 赋值的变量。* @return None*/BaseClass& operator =(const BaseClass& value);public:/*** @Date 2023-07-07* @Author qiaowei* @Contact weiweiqiao@126* @Version 1.0* @Brief 指针字段,类类型数据。*/DataClass* data_;/*** @Date 2023-07-07* @Author qiaowei* @Contact weiweiqiao@126* @Version 1.0* @Brief 字段。*/QString local_;
};#endif // BASECLASS_H
.cpp文件:
#include <QtDebug>#include "base-class.h"BaseClass::BaseClass(QObject* parent): QObject{parent}, data_{new DataClass{}}, local_{"local address"}
{}BaseClass::BaseClass(const BaseClass& value)
{if ((nullptr != &value) && (this != &value)){/*** 注意事项:* 调用父类拷贝构造函数,因为QObjet的构造函数为private,故不可调用。* 拷贝构造函数是构造函数的一种,所有字段都是首次调用初始化,不需要对指针字段进行判断,进行delete避免内存泄漏* 情况。*/// 直接对指针字段进行new。data_ = new DataClass(*(value.data_));local_ = value.local_;}
}BaseClass::~BaseClass()
{// local_字段是基本类型,无需析构。在析构方法中只对指针字段进行处理,避免memory leak。if (nullptr != data_) {delete data_;data_ = nullptr;}
}BaseClass &BaseClass::operator =(const BaseClass& value)
{// value就是当前字段本身,无需赋值,直接返回。if (this == &value) {return *this;}// Avoid memory leak.if (nullptr != data_) {delete data_;data_ = nullptr;}// 按照字段在类中的声明顺序,依次赋值。data_ = new DataClass(*(value.data_));local_ = value.local_;return *this;
}
运行测试:
#include <QApplication>
#include <QtDebug>#include "deprived-test/base_class.h"
#include "deprived-test/data_class.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);BaseClass* base = new BaseClass(nullptr);qDebug()<< base->data_->name_ << endl;qDebug()<< base->data_->level_ << endl;BaseClass base01(*base);base01.data_->name_ = "test";qDebug()<< base->data_->name_ << endl;qDebug()<< base01.data_->name_ <<endl;return a.exec();
}
测试结果:
"" 0 "" "test"
可以看到base01由base赋值,随后对base01的字段进行了修改,打印两者的字段,发现base的字段没有跟随base01的值而改变。所以指针字段分离。
DeprivedClass是BaseClass的子类,在拷贝构造方法,赋值操作符中对父类的相关操作进行调用。
.h
#ifndef DEPRIVEDCLASS_H
#define DEPRIVEDCLASS_H#include <QObject>#include "base-class.h"class DeprivedClass : public BaseClass
{Q_OBJECTpublic:explicit DeprivedClass(QObject *parent = nullptr);/*** @author qiao wei* @contact weiweiqiao@126* @version 1.0* @other Used/Unused* @brief Copy constructor.* @param value DeprivedClass reference.* @return None*/DeprivedClass(const DeprivedClass& value);virtual ~DeprivedClass();DeprivedClass& operator =(const DeprivedClass& value);public:DataClass* deprived_data_;
};#endif // DEPRIVEDCLASS_H
.cpp
#include "deprived-class.h"DeprivedClass::DeprivedClass(QObject *parent): BaseClass{parent}, deprived_data_{new DataClass{}}
{}DeprivedClass::DeprivedClass(const DeprivedClass &value)
{if ((nullptr != &value) && (this != &value)) {// Call copy constructor of base class.BaseClass::BaseClass(value);deprived_data_ = new DataClass(*(value.deprived_data_));}
}DeprivedClass::~DeprivedClass()
{if (nullptr != deprived_data_) {delete deprived_data_;deprived_data_ = nullptr;}// Implicit call destructor of base class.
}DeprivedClass &DeprivedClass::operator =(const DeprivedClass &value)
{if (this == &value) {return *this;}if (nullptr != &value) {// Call assignment operator of base class.BaseClass::operator =(value);// Avoid memory leak.if (nullptr != deprived_data_) {delete deprived_data_;deprived_data_ = nullptr;}// 对DeprivedClass中的字段进行赋值。deprived_data_ = new DataClass(*(value.deprived_data_));}return *this;
}
测试运行代码:
DeprivedClass* d01 = new DeprivedClass{};DeprivedClass d02(*d01);d02.deprived_data_->name_ = "aaa";DeprivedClass* d03 = new DeprivedClass{};*d03 = d02;qDebug()<< d03->deprived_data_->name_ << endl;qDebug()<< d03->deprived_data_ << endl;qDebug()<< &(d02.deprived_data_) << endl;
运行结果:
"aaa" DataClass(0x1caeaf4f760) 0x1000ff5e0
更多推荐
C++中拷贝构造函数和赋值操作符(Copy constructor Assignment operator)
发布评论