C++:运算符重载和“const”成员

hello,各位小伙伴,本篇文章跟大家一起学习《C++:运算符重载》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !

文章目录

    • 赋值运算符重载
      • 1. 运算符重载
      • 2.赋值运算符重载
        • 第一个点
        • 第二个点:
        • 第三个点:
    • 前置++和后置++重载
    • const成员

赋值运算符重载

1. 运算符重载

在《C++:函数重载和引用》里有讲到函数中在,那么和运算符重载有什么不一样呢?

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:关键字 operator 后面接需要重载的运算符符号。
函数原型:返回值类型 operator 操作符(参数列表)

但是并不是所有符号都能重载,要注意:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  5. .*::sizeof?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

举个例子:

class Date
{
public:Date(Date& d){_year = d._year;_month = d._month;_day = d._day;}Date(int year = 1,int month = 1,int day = 1){_year = year;_month = month;_day = day;}// 加const修饰是为了不让传参被改变bool operator==(const Date& d){return _year == d._year && _month == d._month&& _day == d._day;}private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 5, 1);Date d2(d1);//拷贝构造cout << (d1 == d2) << endl;return 0;
}

输出结果是:1,也就是说d1和d2是相等的

// 这里需要注意的是,左操作数是this,指向调用函数的对象bool operator==(const Date& d){return _year == d._year && _month == d._month&& _day == d._day;}

2.赋值运算符重载

第一个点

先来看格式,赋值运算符重载格式:

  • 参数类型:const T&,传递引用可以提高传参效率 //T是类名
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this :要复合连续赋值的含义
Date& operator=(const Date& d){if(this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}

1.先讲讲参数形式为什么是**const T&**和返回值类型:T&,在《C++:构造函数、析构函数、拷贝构造函数》讲到过在对象的传值传参时,会发生拷贝构造,返回临时对象时,也会发生拷贝构造,会降低效率。所以选择传引用传参和用引用做返回值

用引用做返回值还有一个原因是为了支持连续赋值,举个例子:

int main()
{Date d1(2024,5,1);Date d2(1,1,1);Date d3(1,1,1);d3 = d2 = d1;return 0;
}

d2 = d1时调用了函数Date& operator=(const Date& d),会返回一个值,这个值属于什么类型会影响d3,所以返回*this是为了将d2的值赋值给d3,从而实现了连续赋值

2.检测是否自己给自己赋值,自己给自己复制就没意思了,所以直接return *this

第二个点:

赋值运算符只能重载成类的成员函数不能重载成全局函数
原因:

赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

第三个点:

用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝
注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

class Time
{
public:Time(){_hour = 1;_minute = 1;_second = 1;}Time& operator=(const Time& t){if (this != &t){_hour = t._hour;_minute = t._minute;_second = t._second;}return *this;}
private:int _hour;int _minute;int _second;
};class Date
{
private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t;
};
int main()
{Date d1;Date d2;d1 = d2;return 0;
}

在这里会调用Time类的赋值运算符重载完成赋值

这里有小伙伴会说:既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?当然像日期类这样的类是没必要的。但是存在即合理,看以下例子:

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2 = s1;return 0;
}

这个是用类来实现栈,为什么程序会崩溃呢?
用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝

注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。

逐字节拷贝:

  1. 也就是说s2的_arry的地址指向了s1的_arry的地址
  2. 那么编译器为s2的_arry开辟的空间消失了
  3. 导致内存泄漏
  4. 在最后销毁时,将同一块空间释放了两次,程序崩溃

图解:
在这里插入图片描述

前置++和后置++重载

根据前面所讲,
函数名字为:关键字 operator 后面接需要重载的运算符符号。
函数原型:返回值类型 operator 操作符(参数列表)

那么怎么区分前置++和后置++重载的函数,来看:
在C++中,前置++和后置++运算符可以被重载为成员函数或友元函数。要区分重载的前置++和后置++函数,你需要注意两点:

  1. 函数参数列表:前置++和后置++函数的参数列表应该是不同的,以便编译器可以区分它们

  2. 函数的返回类型:前置++函数应该返回引用,而后置++函数应该返回值

下面是一个示例,展示了如何重载前置++和后置++运算符:

#include <iostream>class Counter {
public:Counter() : count(0) {}// 前置++运算符重载Counter& operator++() {++count;return *this;}// 后置++运算符重载Counter operator++(int) {Counter temp = *this;++(*this);return temp;}void display() {std::cout << "Count: " << count << std::endl;}
private:int count;
};int main() {Counter c1, c2;// 前置++++c1;c1.display();  // 输出: Count: 1// 后置++c2++;c2.display();  // 输出: Count: 1return 0;
}

在这个示例中,前置++运算符被重载为成员函数operator++(),后置++运算符被重载为成员函数operator++(int)。前置++函数返回引用,而后置++函数返回值。

注意:C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递

const成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改

只不过这个const放的位置有点奇怪,因为在类的成员函数参数列表中this指针已经是固定在第一位的,只是看不到,所以要这么做:

class Date
{
public:void Print() const{cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}
private:int _year;int _month;int _day;
};

那么const修饰后的对象调用函数,又与普通的对象调用函数有什么不一样呢?
来看下列代码:

#include<iostream>
using namespace std;class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << "Print()" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}void Print() const{cout << "Print()const" << endl;cout << "year:" << _year << endl;cout << "month:" << _month << endl;cout << "day:" << _day << endl << endl;}
private:int _year; // 年int _month; // 月int _day; // 日
};
void Test()
{Date d1(2022, 1, 13);d1.Print();const Date d2(2022, 1, 13);d2.Print();
}int main()
{Test();return 0;
}

运行结果:在这里插入图片描述
很明显,d1不能调用void Print() const,d2不能调用void Print()

问题又来了:

  1. const对象内可以调用其它的非const成员函数吗?
  2. 非const对象内可以调用其它的const成员函数吗?

总结:

  1. const 对象可以调用非 const 成员函数吗?

    • 是的,const 对象可以调用非 const 成员函数。因为 const 对象的调用不会改变对象的状态,只是限制了对成员变量的修改,所以它可以安全地调用非 const 成员函数。
  2. 非 const 对象可以调用 const 成员函数吗?

    • 是的,非 const 对象可以调用 const 成员函数。因为非 const 对象的调用不会限制对成员变量的修改,所以它可以安全地调用 const 成员函数。
  3. const 成员函数内可以调用其他的非 const 成员函数吗?

    • 是的,const 成员函数内可以调用其他的非 const 成员函数。因为 const 成员函数承诺不会修改对象的状态,但它可以通过调用其他非 const 成员函数来实现某些功能。
  4. 非 const 成员函数内可以调用其他的 const 成员函数吗?

    • 是的,非 const 成员函数内可以调用其他的 const 成员函数。因为非 const 成员函数没有限制对成员变量的修改,所以它可以安全地调用 const 成员函数。

总的来说,const 成员函数提供了对象只读的访问权限,并不限制调用其他成员函数的类型;而非 const 成员函数可以调用任何类型的成员函数。

在这个示例中,callNonConstFromConst()函数是一个const成员函数,它调用了非const成员函数nonConstFunc(),这是允许的。但是,如果你尝试在非const成员函数中调用const成员函数(例如callConstFromNonConst()),编译器将会报错。

简单理解就是:权限问题,const非const,权限放大,是肯定不行的;反过来权限缩小,是可以的。

好啦,这篇文章就到此结束了
所以你学会了吗?

好啦,本章对于《C++:运算符重载和“const”成员》的学习就先到这里,如果有什么问题,还请指教指教,希望本篇文章能够对你有所帮助,我们下一篇见!!!

如你喜欢,点点赞就是对我的支持,感谢感谢!!!

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

迅雷下载不了的资源怎么下载?

我想下载Boost库&#xff0c;但是下载不下来 用迅雷下载是一直卡在0k 后来尝试在centos上用wget进行下载&#xff0c;竟然可以 wget https://boostorg.jfrog.io/artifactory/main/release/1.85.0/source/boost_1_85_0.tar.gz

揭开ChatGPT面纱(一):准备工作(搭建开发环境运行OpenAI Demo)

文章目录 序言&#xff1a;探索人工智能的新篇章一、搭建开发环境二、编写并运行demo1.代码2.解析3.执行结果 本博客的gitlab仓库&#xff1a;地址&#xff0c;本博客对应01文件夹。 序言&#xff1a;探索人工智能的新篇章 随着人工智能技术的飞速发展&#xff0c;ChatGPT作为…

2024燃动智火-业务视角的中国企业AI+学习发展报告

来源&#xff1a;新华三 学习型组织的数字化转型是众多企业关注的焦点&#xff0c;数字战略需要人才升级&#xff0c;数字 化学习加速人才培养。AI 技术在学习中的运用&#xff0c;为企业学习型组织的数字化转型插 上了飞翔的翅膀。这份报告解码了AI 时代企业的学习发展&#…

混合现实(MR)开发框架

混合现实&#xff08;MR&#xff09;开发框架为开发者提供了构建MR应用程序所需的基本工具和功能。它们通常包括3D引擎、场景图、输入系统、音频系统、网络功能以及支持同时处理现实世界和虚拟世界信息的功能。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&…

springboot+ssm基于Java的小型企业银行账目管理系统代码Lw

本毕业设计课题要求学生基于软件工程方法&#xff0c;根据课题的需求&#xff0c;给出小型企业银行账目管理系统概要设计、详细设计、数据库的设计以及系统实现和测试&#xff0c;并撰写规范的毕业设计说明书。该系统的主要模块有&#xff1a;系统管理、帐目管理、查询统计、用…

如何使用 ArcGIS Pro 制作边界晕渲效果

在某些出版的地图中&#xff0c;边界有类似于“发光”的晕渲效果&#xff0c;这里为大家介绍一下如何使用ArcGIS Pro 制作这种晕渲效果&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的行政区划数据&#xff0c;除了行政区划数据&#xff0c…

【Flutter】多语言方案二:GetX 版

介绍 多语言方案&#xff1a;GetX版&#xff0c;需要手动自定义字符串引用常量&#xff0c;优点不需要自己管理状态。 目录 介绍运行效果一、安装 GetX二、使用1.语言配置 在lib/core下创建一个language文件夹&#xff0c;文件夹下创建一个local.dart文件2.language文件夹下创…

程序员自由创业周记#32:新产品构思

程序员自由创业周记#32&#xff1a;新产品构思 新作品 我时常把自己看做一位木匠&#xff0c;有点手艺&#xff0c;能做一些作品养活自己。而 加一、Island Widgets、Nap 就是我的作品。 接下来在持续维护迭代的同时&#xff0c;要开启下一个作品的创造了。 其实早在2022的1…

进程间通信(1)管道

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

【C语言】内存函数-memcpy-memmove-memset...用法及实现,沉淀自己!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. memcpy函数使用和模拟实现 2. memmove使用和模拟实现 3. memset函数的使用 4. memcmp函数的使用 1. memcpy函数使用和模拟实现 <string.h>-------…

Buildroot系统构建学习笔记(以百问网imx6ullPro开发板为例)

一、Builroot是什么&#xff1f; Buildroot是一组Makefile和补丁&#xff0c;可简化并自动化地为嵌入式系统构建完整的、可启动的Linux环境(包括bootloader、Linux内核、包含各种APP的文件系统)。Buildroot运行于Linux平台&#xff0c;可以使用交叉编译工具为多个目标板构建嵌…

沉思录 (梁实秋)

链接&#xff1a;https://pan.quark.cn/s/8e27564b02f5

Python 检测当前系统的内存及硬盘资源,发送邮件告警通知(告警内容包含告警语句及网卡和系统版本时间)

颜色块 rootbogon:~ 2024-04-18 16:16:40# cat DefaultColor.py ######################################################################### # File Name: DefaultColor.py # Author: eight # Mail: 18847097110163.com # Created Time: Thu 11 Apr 2024 10:…

H3C之GRE VPN

华子目录 GRE实验测试 MGRE实验 GRE实验 第一步&#xff1a;接口配置IP地址 <H3C>sys System View: return to User View with CtrlZ. [H3C]sysname r1 [r1]int g0/0 [r1-GigabitEthernet0/0]ip add 192.168.1.1 24 [r1-GigabitEthernet0/0]int g0/1 [r1-GigabitEtherne…

短视频素材哪里去找?推荐几个视频素材免费下载的网站

高质量的资源&#xff0c;会让你的视频创作更加生动和具有吸引力。下面我为你介绍世界各地的优质无水印视频素材网站&#xff0c;以拓宽你的创作视野&#xff0c;帮助你在这个视觉革命的时代中脱颖而出。 1. 蛙学府&#xff08;中国&#xff09; 提供各种类别的优质高清视频素…

视频监控平台的web客户端看到的视频画面是黑屏时的处理方法

目录 一、问题描述 二、问题分析 &#xff08;一&#xff09;总体分析 &#xff08;二&#xff09;视频流传输问题的原因分析 1、网络问题 2、设备问题 3、配置和设置问题 4、兼容性问题 三、诊断和排查步骤 &#xff08;一&#xff09;编码方式问题的处理办法 &…

Redis中的订阅发布(一)

订阅发布 概述 Redis的发布与订阅功能由PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令组成。通过执行SUBSCRIBER命令&#xff0c;客户端可以订阅一个或多个频道&#xff0c;从而成为这些频道的订阅者(subscribe)&#xff1a; 每当有其他客户端向被订阅的频道发送消息(message)时&…

同旺科技 USB TO SPI / I2C适配器读写24LC256--页写

所需设备&#xff1a; 1、USB 转 SPI I2C 适配器&#xff1b;内附链接 2、24LC256芯片 适应于同旺科技 USB TO SPI / I2C适配器升级版、专业版&#xff1b; 从00地址开始写入64个字节&#xff0c;然后再将64个字节读回&#xff1b; 页写时序&#xff1a; 读时序&#xff1a…

iOS开发 刻度盘 仪表盘,圆点按钮滑动控制,渐变色

最近项目需要&#xff0c;想做一个渐变色的刻度盘&#xff0c;圆形按钮滑动控制&#xff0c;所以 用oc写了一下&#xff0c;代码没附上&#xff0c;想看代码可以私信联系&#xff0c;效果如下图。 部分代码 self.drawCenter CGPointMake(self.frame.size.width / 2.0, self.f…

姑苏寻韵~庆开放原子开源大赛 OpenTiny 前端 Web 应用开发挑战赛路演圆满落幕。

春日已至&#xff0c;姑苏古城迎来了一场编程的盛宴——开放原子开源大赛OpenTiny前端Web应用开发挑战赛。历时三个月的激烈角逐&#xff0c;OpenTiny与众多开发者携手共赴这场智慧的较量。决赛路演于4月14日在苏州&#xff08;太湖&#xff09;产业软件园圆满落下帷幕~ 开放原…