在c++学习笔记(8)中,介绍了拷贝构造函数的概念:涉及到深拷贝和浅拷贝的概念:

拷贝构造函数:每一个类都有一个都有一个拷贝构造函数,用于拷贝对象。拷贝构造函数可以用来创建一个对象,并用另一个对象的数据初始化新建对象。缺省的拷贝构造函数和赋值运算符(=)进行对象赋值采用的是一种所谓的“浅拷贝”,即如果数据域是一个指向其他对象的指针,那么就会简单复制指针保存的地址值,而不是复制指针指向的对象的内容。

如果没有显式的定义拷贝构造函数,C++会为每个类都定义一个缺省的拷贝构造函数。这个函数简单的将参数对象中的数据域复制给新建对象中相应的副本。

比如在C++学习笔记(8)中遇到course类:需要对拷贝构造函数进行定义,使其进行深拷贝:

为什么Course类中,要自定义拷贝构造函数,实现深拷贝?

原因::因为course类数据域有指向数组的指针students,如果使用上述的浅拷贝,在copy过程中,两个指针拷贝时,保存了相同地址,即指向了相同的地址。但是在程序执行完毕时,对象需要调用析构函数delete指针students,但是如果两个对象是copy的关系,则会调用两次析构函数删除相同的指针,这是程序就会报错。所以需要自定义拷贝构造函数,实现深拷贝。使两个对象中的数据域中指针students相互独立,就不会出现上述情况。

重载赋值运算符

赋值运算符=与缺省的拷贝构造函数一样,执行的是“浅拷贝”。但是,即使重新定义了拷贝构造函数,也不能改变赋值运算符(=)的缺省行为(即进行的操作是浅拷贝)。为了改变(=)缺省行为,需要重载=运算符

course.h文件

#ifndef COURSE_H
#define COURSE_H
#include <string>using namespace std;class Course
{private:string courseName;string* students;int numberOfStudents;int capacity;public:Course(const string& courseName, int capacity);  // 构造函数~Course();    // 析构函数Course(const Course& course);    // 拷贝构造函数string getCourseName() const;void addStudent(const string& name);   void dropStudent(const string& name);string* getStudents() const;int getNumberOfStudents() const;Course& operator=(const Course& course);   // 重载=运算符
};
#endif

course.cpp文件

#include <iostream>
#include <string>
#include "E:\back_up\code\c_plus_code\test_test\external_file\course.h"using namespace std;
Course::Course(const string& courseName, int capacity)
{numberOfStudents = 0;this->courseName = courseName;this->capacity = capacity;students = new string[capacity];   // 动态分配内存空间
}Course::~Course()
{delete []students;
} Course::Course(const Course& course)
{numberOfStudents = course.numberOfStudents;courseName = course.courseName;capacity = course.capacity;students = new string[capacity];for(int i=0;i<numberOfStudents; i++)     // 实现deepcopy {students[i] = course.students[i];}
}string Course::getCourseName() const
{return courseName;
}void Course::addStudent(const string& name)
{if(numberOfStudents>=capacity){cout << "The class hsa been fuul" << endl;exit(0);    // 课程添加人数已满,退出程序 }students[numberOfStudents++] = name;
}void Course::dropStudent(const string& name)
{int index = 0;bool found_flag = false;for(int i=0; i<numberOfStudents; i++){if(name==students[i]){index = i;found_flag = true;break;}//index++;}if(found_flag){for(int j=index; j<numberOfStudents-1; j++){students[j] = students[j+1];}numberOfStudents--;cout << "Student " << name << " is successfully deleted from class!" << endl;}else{cout << "The student not in the class" << endl;exit(0); } }string* Course::getStudents() const
{return students;
}int Course::getNumberOfStudents() const
{return numberOfStudents;
}// 重载=运算符
Course& Course::operator=(const Course& course)
{if(this!=&course)   //如果是对象自己给自己复制,则不进行操作 {courseName = course.courseName;numberOfStudents = course.numberOfStudents;capacity = course.capacity;// 删除就的指针,理解:缺省的=运算符和拷贝构造函数,会首先创建一个对象// 再将成员数据逐个赋值,这里的=在创建了新的对象后,后续的默认操作没有进行(逐个成员复制值)// 就被重载,所以在重载中delete []students时,此时的students还没有复制course对象中的指针值// 所以直接delete掉。不会影响course中students指向的内容// delete p的本质是将p指向的内存(由new分配的)释放掉,使p成为一个悬空的指针。 delete [] this->students;   // delete the old arraystudents = new string[capacity]; for(int i=0; i<numberOfStudents; i++){students[i] = course.students[i];}} return *this;
}

main.cpp文件

#include <iostream>
#include <string>
#include "E:\back_up\code\c_plus_code\test_test\external_file\course.h"using namespace std;void displayStudents(string*, int);
void printStudentsList(const Course&);int main(int argc, char *argv[])
{Course course1("Java class", 20);Course course2("C++ class", 30);course1.addStudent("zhangsan");course1.addStudent("lisi");course2 = course1;    // =运算符 course1.addStudent("zhaoliu");course2.addStudent("wangwu");string* student_list1 = course1.getStudents();    string* student_list2 = course2.getStudents();int number1 = course1.getNumberOfStudents();int number2 = course2.getNumberOfStudents();displayStudents(student_list1, number1);displayStudents(student_list2, number2);course1.dropStudent("zhangsan");course2.dropStudent("wangwu");printStudentsList(course1);printStudentsList(course2);return 0;
}void displayStudents(string* student, int studentNumber)
{for(int i=0; i<studentNumber; i++){cout << student[i] << endl;}cout << endl;
} void printStudentsList(const Course& course)
{string* student_list = course.getStudents();int student_number = course.getNumberOfStudents();for(int i=0; i<student_number; i++){cout << student_list[i] << endl;}cout << endl;
}

运行结果:

注:(书本)

拷贝构造函数,析构函数,=运算符,称为三规则或者大三元,如果他们没有显式的说明,将会被编译器自动生成,同时具有自己的“缺省行为”。如果类中有数据成员指向动态生成的数组或者对象,那么需要对大三元对应的内容进行修改。其中一个,其他两个也做对应的修改。

c++学习笔记(12) 需要对对象做拷贝时(深拷贝,浅拷贝),如何重载赋值运算符相关推荐

  1. Kotlin学习笔记12——数据类和密封类

    Kotlin学习笔记12--数据类和密封类 前言 数据类 在类体中声明的属性 复制 componentN 解构声明 密封类 尾巴 前言 上一篇,我们学习了Kotlin中的拓展,今天继续来学习Kotli ...

  2. C++学习笔记-第4单元-对象和类(基础)

    C++学习笔记 文章目录 C++学习笔记 第4单元 对象和类(基础) 单元导读 4.1 用类创建对象 4.1.1 对象和类 4.1.2 创建对象并访问 4.2 对象拷贝.分离声明与实现 4.2.1 对 ...

  3. HALCON 20.11:深度学习笔记(12)---语义分割

    HALCON 20.11:深度学习笔记(12)--- 语义分割 HALCON 20.11.0.0中,实现了深度学习方法. 本章解释了如何使用基于深度学习的语义分割,包括训练和推理阶段. 通过语义分割, ...

  4. 《JavaScript高级程序设计》读书笔记 -12.1 window对象

    <JavaScript高级程序设计>读书笔记 -12.1 window对象 12.1 window对象 12.1.1 Global作用域 12.1.2 窗口关系[不是很懂] 12.1.3 ...

  5. Python学习笔记 (类与对象)

    Python学习笔记 (类与对象) 1.类与对象 面向对象编程语言类: 一个模板, (人类)-是一个抽象的, 没有实体的对象: (eg: 张三, 李四) 属性: (表示这类东西的特征, 眼睛, 嘴巴, ...

  6. 【计算机网络学习笔记12】交换技术(上)

    [计算机网络学习笔记12]交换技术(上) 经典局域网的交换技术 概念 以太网是由Xerox公司创建并由Xerox.intel和DEC公司联合开发的基带局域网规范,是当今现有局域网采用的最通用的通信协议 ...

  7. JavaScript学习笔记02【基础——对象(Function、Array、Date、Math)】

    w3school 在线教程:https://www.w3school.com.cn JavaScript学习笔记01[基础--简介.基础语法.运算符.特殊语法.流程控制语句][day01] JavaS ...

  8. 【数据库学习笔记】——cursor游标对象

    目录 1.创建cursor对象 2.cursor对象常用方法 3.操作数据库的常见流程(五部曲) 课程视频链接: 第14节 Python操作数据库_哔哩哔哩_bilibili666https://ww ...

  9. Linux学习笔记12——配置ftp、squid、Tomcat、Samba、MySQL主从

    Linux学习笔记12 Linux学习笔记12 配置FTP服务 配置pure-ftpd 开机启动 上传下载文件 配置vsftpd CentOS 70安装配置Vsftp服务器 搭好vsftp之后出现55 ...

最新文章

  1. .net 获取字符串中的第一个逗号的位置_用EXCEL合并同列字符串
  2. 查看无线网卡工作模式
  3. 莆田学院计算机科学与技术分数,莆田学院录取分数线2021是多少分(附历年录取分数线)...
  4. java 拷贝文件夹的实现
  5. CanFestival移植到STM32F103
  6. C#中面向对象编程中的函数式编程
  7. 开启6.0 sd卡读写权限_解了摄影师的燃眉之急:入手雷克沙TF卡,一卡多用速度超快...
  8. Http协议对格式、请求头、方法
  9. libgsm.a relocation R_X86_64_PC32 can not be used when making a shared object; recompile with -fPIC
  10. 基于算符优先文法的逆波兰表达式及计算
  11. 电子书下载:深入解析Windows操作系统第6版 Windows Internals 6th Part1, Part2
  12. Class ZipArchive not found,安装zip扩展
  13. 74HC/LS/HCT/F系列芯片的区别及使用[转]
  14. android获取GPS权限
  15. 如何绕过mac地址过滤_上传图片shell绕过过滤的几种方法
  16. 工业无线技术在未来工厂运营中的机遇和挑战
  17. INTERVAL 用法
  18. 训练集和测试集的分布差距太大有好的处理方法吗?
  19. 机器学习训练模型的大体流程
  20. kubernetes 曲线救国式下载 kubeadm 1.21 相关镜像

热门文章

  1. Sentinel降级简介_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0038
  2. STM32工作笔记0074---UCOSIII 任务管理(中)
  3. springmvc 异常001---在SpringMVC中使用@RequestBody注解处理json时,报出HTTP Status 415的解决方案
  4. C语言警告warning C4018: '' : signed/unsigned mismatch
  5. 正则表达式 判断 连号如“123456”、同号如“888888”、连同号如“112233”“222333”...
  6. 初学angularJS 个人总结 错误排除
  7. 软件自动化测试题,软件自动化测试模拟题.doc
  8. linux感染十字符病毒,linux下如何刪除十字符libudev.so病毒文件
  9. 3d激光雷达开发(平面映射)
  10. 随想录(libc.so和ld.so调试)