C++:拷贝构造函数、赋值运算符重载

目录

一、拷贝构造函数

拷贝构造的特点

二、赋值运算符重载

2.1 运算符重载

2.2 赋值运算符重载

赋值运算符重载的特点


一、拷贝构造函数

    如果一个构造函数的第一个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数。

拷贝构造的特点

1. 拷贝构造函数是构造函数的⼀个重载。

2. 拷贝构造函数的第一个参数必须是类类型对象的引用,使用传值方式编译器直接报错,因为语法逻辑上会引发无穷递归调用,拷贝构造函数也可以多个参数,但是第一个参数必须是类类型对象的引用,后面的参数必须有缺省值。

3. C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。

4. 若未显式定义拷贝构造,编译器会生成自动生成拷贝构造函数,自动生成的拷贝构造对内置类型成员变量会完成浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造。

5. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器自动生成的拷贝构造就可以完成需要的拷贝,所以不需要我们显示实现拷贝构造。像Stack这样的类,虽然也都是内置类型,但 是_a指向了资源,编译器自动生成的拷贝构造完成的浅拷贝不符合我们的需求,所以需要 我们自己实现深拷贝(对指向的资源也进行拷贝)。像MyQueue这样的类型内部主要是自定义类型 Stack成员,编译器自动生成的拷贝构造会调用Stack的拷贝构造,也不需要我们显示实现 MyQueue的拷贝构造,这里还有⼀个小技巧,如果⼀个类显示实现了析构并释放资源,那么他就 需要显示写拷贝构造,否则就不需要。

6. 传值返回会产生一个临时对象调用拷贝构造,传值引用返回,返回的是返回对象的别名(引用),没有产生拷贝,但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使用引用返回是有问题的,这时的引用相当于⼀个野引用,类似一个野指针一样,传引用返回可以减少拷贝,但是⼀定要确保返回对象,在当前函数结束后还在,才能用引用返回。

#include<iostream>
using namespace std;
class Date
{
public:
 Date(int year = 1, int month = 1, int day = 1)
 {
 _year = year;
 _month = month;
 _day = day;
 }
Date(const Date& d)
{
 _year = d._year;
 _month = d._month;
 _day = d._day;
 }
private:
 int _year;
 int _month;
 int _day;
};

  这里可以完成拷贝,但是不是拷贝构造,只是⼀个普通的构造

Date d2(&d1);
 d1.Print();
 d2.Print();

 这样写才是拷贝构造,通过同类型的对象初始化构造,而不是指针  

Date d3(d1);
 d2.Print();

 也可以这样写,这里也是拷贝构造  

Date d4 = d1;
 d2.Print();

二、赋值运算符重载

2.1 运算符重载

• 当运算符被用于类类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义。C++规 定类类型对象使用运算符时,必须转换成调用对应运算符重载,若没有对应的运算符重载,则会编 译报错。

• 运算符重载是具有特殊名字的函数,他的名字是由operator和后面要定义的运算符共同构成,和其 他函数⼀样,它也具有其返回类型和参数列表以及函数体。

• 重载运算符函数的参数个数和该运算符作用的运算对象数量⼀样多,⼀元运算符有⼀个参数,二元 运算符有两个参数,二元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第二个参数。

• 如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算 符重载作为成员函数时,参数比运算对象少⼀个。

• 运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。

• 不能通过连接语法中没有的符号来创建新的操作符:比如operator@。

• .*  ::  sizeof  ?:  . 注意以上5个运算符不能重载。

• 重载操作符⾄少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: int operator+(int x, int y) • ⼀个类需要重载哪些运算符,是看哪些运算符重载后有意义,比如Date类重载operator-就有意 义,但是重载operator+就没有意义。

• 重载++运算符时,有前置++和后置++,运算符重载函数名都operator++,无法很好的区分。 C++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。

• 重载>时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位 置,第⼀个形参位置是左侧运算对象,调用时就变成了对象。

bool operator==(const Date& d1, const Date& d2)
{
 return d1._year == d2._year
 && d1._month == d2._month
 && d1._day == d2._day;
}

这里举了个关于判断日期是否相同的运算符重载。

重载为全局的面临对象访问私有成员变量的问题

有几种方法可以解决:

1、成员放公有(一般不推荐,风险比较大)

2、Date提供getxxx函数

3、友元函数

4、重载为成员函数

2.2 赋值运算符重载

     赋值运算符重载是⼀个默认成员函数,用于完成两个已经存在的对象直接的拷贝赋值,这里要注意跟拷贝构造区分,拷贝构造用于⼀个对象拷贝初始化给另⼀个要创建的对象。

赋值运算符重载的特点

1. 赋值运算符重载是⼀个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成 const当前类类型引用,否则会传值传参会有拷贝。

2. 有返回值,且建议写成当前类类型引用,引用返回可以提高效率,有返回值目的是为了支持连续赋值场景。

3. 没有显式实现时,编译器会自动生成⼀个默认赋值运算符重载,默认赋值运算符重载行为跟默认拷贝构造函数类似,对内置类型成员变量会完成浅拷贝(⼀个字节⼀个字节的拷贝),对自定义类型成员变量会调用他的赋值重载函数。

4. 像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器自动生成的赋值运算符重载就 可以完成需要的拷贝,所以不需要我们显示实现赋值运算符重载。像Stack这样的类,虽然也都是 内置类型,但是_a指向了资源,编译器自动生成的赋值运算符重载完成的浅拷贝不符合我 们的需求,所以需要我们自己实现深拷贝(对指向的资源也进行拷贝),像MyQueue这样的类型内部 主要是自定义类型Stack成员,编译器自动生成的赋值运算符重载会调用Stack的赋值运算符重载, 也不需要我们显示实现MyQueue的赋值运算符重载,这里还有⼀个小技巧,如果⼀个类显示实现 了析构并释放资源,那么他就需要显示写赋值运算符重载,否则就不需要。

class Date
{
public:
 Date(int year = 1, int month = 1, int day = 1)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 Date(const Date& d)
 {
 cout << " Date(const Date& d)" << endl;
 _year = d._year;
 _month = d._month;
 _day = d._day;
 }
 // 传引⽤返回减少拷⻉ 
 // d1 = d2;
 Date& operator=(const Date& d)
 {
 // 不要检查⾃⼰给⾃⼰赋值的情况 
 if (this != &d)
 {
 _year = d._year;
 _month = d._month;
 _day = d._day;
 }
 // d1 = d2表达式的返回对象应该为d1,也就是*this 
 return *this;
 }
 void Print()
 {
cout << _year << "-" << _month << "-" << _day << endl;
 }
private:
 int _year;
 int _month;
 int _day;
};
int main()
{
 Date d1(2024, 7, 5);
 Date d2(d1);
 Date d3(2024, 7, 6);
 d1 = d3;
 // 需要注意这⾥是拷⻉构造,不是赋值重载 
 // 请牢牢记住赋值重载完成两个已经存在的对象直接的拷⻉赋值 
 // ⽽拷⻉构造⽤于⼀个对象拷⻉初始化给另⼀个要创建的对象 
 Date d4 = d1;
 return 0;
}

    本篇关于拷贝构造函数和赋值运算符重载的内容就到这里了,希望对各位有帮助,如果有错误欢迎指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/873913.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python篇】matplotlib超详细教程-由入门到精通(上篇)

文章目录 第一部分&#xff1a;基础概念与简单绘图1.1 matplotlib 简介1.2 创建第一个折线图1.3 图表的基本组成元素 第二部分&#xff1a;图表样式与修饰2.1 修改图表样式2.2 添加图例2.3 调整坐标轴与刻度 第三部分&#xff1a;绘制不同类型的图表3.1 散点图 (Scatter Plot)3…

JVM 调优篇2 jvm的内存结构以及堆栈参数设置与查看

一 jvm的内存模型 2.1 jvm内存模型概览 二 实操案例 2.1 设置和查看栈大小 1.代码 /*** 演示栈中的异常:StackOverflowError** author shkstart* create 2020 下午 9:08** 设置栈的大小&#xff1a; -Xss (-XX:ThreadStackSize)** -XX:PrintFlagsFinal*/ public class S…

关于ansible自动化运维工具

成长路上不孤单&#x1f60a;【14后&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff01;&#xff01;&#xff01;&#xff01;&#xff…

Android SystemUI组件(05)状态栏-系统状态图标显示管理

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注下方 SystemBars分析中状态栏中的部分-系统状态图标显示&管理 即可。 1 系统状态图标显…

Error when attempting to add data source to Azure OpenAI api

题意&#xff1a;尝试向 Azure OpenAI API 添加数据源时出现错误 问题背景&#xff1a; My code is working for a call to Azure OpenAI when I dont have a datasource added. However, when I do add my datasource with the following parameters I get an error: 当我没…

Dubbo精要

1、为什么需要 Dubbo&#xff1f; 分布式系统中的服务调用和协调问题&#xff1a;在分布式系统中&#xff0c;服务之间的相互依赖会导致复杂的通信和协调问题。Dubbo提供了高效的服务调用和自动注册、发现等功能&#xff0c;使得构建分布式应用程序更加容易。服务治理和服务调…

LeetCode 热题 100 回顾5

干货分享&#xff0c;感谢您的阅读&#xff01;原文见&#xff1a;LeetCode 热题 100 回顾_力code热题100-CSDN博客 一、哈希部分 1.两数之和 &#xff08;简单&#xff09; 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标…

CentOS Stream 8中安装和使用 Docker

docker安装包-CSDN博客 〇、常用的docker命令 docker的作用&#xff1a; 快速进行软件的安装&#xff0c;便于软件环境的维护 docker的镜像: 压缩了指定软件的安装包的文件。使用镜像文件创建容器 docker的容器: 容器可以理解为就是一台小电脑。安装的linux系统&am…

C++入门基础篇

引言 说到编程语言常常听到的就是C语言C Java 。C语言是面向过程的&#xff0c;C是和Java是面向对象的&#xff0c;那么什么是面向对象呢&#xff1f;什么又是面向过程呢&#xff1f;C是什么&#xff1f;封装、继承、多态是什么&#xff1f;且听我絮絮叨叨。 C入门基础 1.命名…

SpringBoot OAuth2自定义登陆/授权页

背景 5 月份的时候&#xff0c;我实践并整理了一篇博客&#xff1a;SpringBoot搭建OAuth2&#xff0c;该博客完成之后&#xff0c;很长一段时间里我都有种意犹未尽的感觉。诚然&#xff0c;我把OAuth2搭起来了&#xff0c;各种场景的用例也跑通了&#xff0c;甚至源码也看了&am…

《花100块做个摸鱼小网站! 》第六篇—将小网站部署到云服务器上

⭐️基础链接导航⭐️ 服务器 → ☁️ 阿里云活动地址 看样例 → &#x1f41f; 摸鱼小网站地址 学代码 → &#x1f4bb; 源码库地址 一、前言 到这一篇我们终于把环境搭好&#xff0c;也做好了几个热搜小组件&#xff0c;为了让我们方便展示成果或者方便自己摸鱼&#xff0c…

2024最新!Facebook手机版和网页版改名教程!

Facebook作为全球最大的社交平台之一&#xff0c;允许用户自定义名字和昵称。在Facebook更新姓名可以帮助您更好的展现账号形象。本文将为您提供详细的步骤指导&#xff0c;帮助您在手机APP和网页版上轻松完成Facebook改名操作。 Facebook手机版改名 打开Facebook APP并登录账号…

DataGridView用法合集【精品】

目录 1.当前的单元格属性取得、变更 2.DataGridView编辑属性 3.DataGridView最下面一列新追加行非表示 4.判断当前选中行是否为新追加的行 5. DataGridView删除行可否设定 6. DataGridView行列不表示和删除 7. DataGridView行列宽度高度设置为不能编辑 8. DataGridView行…

SQL进阶技巧:如何利用SQL解决趣味赛马问题?| 非等值关联匹配问题

目录 0 问题描述 1 数据准备 2 问题分析 方法一:先分后合思想 方法2:非等值关联匹配 3 小结 0 问题描述 有一张赛马记录表,如下所示: create table RacingResults ( trace_id char(3) not null,race_date date not null, race_nbr int not null,win_name char(30) n…

【北京迅为】《STM32MP157开发板使用手册》-第十四章 QtE5.12应用开发

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

企业品牌声量统计怎么做?有没有什么工具?

企业在进行社交媒体推广宣传的过程中&#xff0c;通常需要关注品牌声量&#xff0c;借此衡量品牌传播效果、进行投放营销复盘等。也可以辅助下一步品牌策略的制定。那品牌声量是什么&#xff0c;怎么去统计这个品牌声量数据呢&#xff1f; 品牌声量是什么&#xff1f; 简单来…

mysql笔记3(数据库、表和数据的基础操作)

文章目录 一、数据库的基础操作1. 显示所有的仓库(数据库)2. 创建数据库注意(命名规范)&#xff1a; 3. 删除数据库4. 查看创建数据库的SQL5. 创建数据库时跟随字符编码6. 修改数据库的字符编码 二、表的基础操作1. 引入表的思维2. 引用数据库3. 查看该数据库下面的表4. 创建表…

全网最适合入门的面向对象编程教程:46 Python函数方法与接口-函数与事件驱动框架

全网最适合入门的面向对象编程教程&#xff1a;46 Python 函数方法与接口-函数与事件驱动框架 摘要&#xff1a; 函数是 Python 中的一等公民,是一种可重用的代码块,用于封装特定的逻辑&#xff1b;事件驱动框架是一种编程模式&#xff0c;它将程序的控制流转移给外部事件,如用…

vscode docker debug python

1. 安装Vscode插件 ”Docker“”Dev Containers““Remote - ssh” 2. 进入Docker环境 点击左侧 Docker图标&#xff0c;选择Containers 对容器进行右键启动 生成新页面直接进行选择文件路径即可&#xff0c;之后得操作均在容器内进行

6.1排序——插入排序与希尔排序

本篇博客来梳理两种常见排序算法&#xff1a;插入排序与希尔排序 常见的排序算法如图 写排序算法的原则&#xff1a;先写单趟&#xff0c;再写整体 一、直接插入排序 1&#xff0e;算法思想 先假定第一个数据有序&#xff0c;把第二个数据插入&#xff1b;再假设前两个数据…