C++中拷贝构造函数和赋值操作符(Copy constructor Assignment operator)

编程入门 行业动态 更新时间:2024-10-06 15:23:15

C++中拷贝构造函数和<a href=https://www.elefans.com/category/jswz/34/1768663.html style=赋值操作符(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)

本文发布于:2024-02-28 07:37:20,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1769111.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:赋值   函数   操作   Copy   Assignment

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!