C++类和对象:赋值重载,const成员

文章目录

    • 1.赋值运算符重载
      • 1.1运算符重载
      • 1.2 赋值运算符重载
      • 1.3 前置++和后置++重载
    • 2.日期类的实现
    • 3. const成员函数
    • 4 取地址及const取地址操作符重载

在这里插入图片描述
上文介绍了前三个默认成员函数,本文会介绍剩下三个, 赋值重载会重点展开。

1.赋值运算符重载

1.1运算符重载

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

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

我们知道,类是不能用符号直接进行比较的,但如果要用 运算符 > 来比较类A是否大于类B,此时就可以重载运算符>:(Date类举例)

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool operator>(Date& tmp){return this->_year > tmp._year;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 2, 2);Date d2(2021, 2, 2);//使用重载后d1和d2就可以按照自己设定的规则比较cout << (d1 > d2) << endl;
}

注意:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@(本来@就不是运算符,不能重载)
  2. 重载操作符必须有一个类的类型参数
  3. 不能重载内置类型的运算符例如:内置的整型+,不 能改变其含义。
  4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this(下面的代码Date类做个解释):
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//看似只有一个参数,其实隐藏了一个固定的参数this,并且是固定的第一个参数bool operator>(Date& tmp){return this->_year > tmp._year;}
private:int _year;int _month;int _day;
};
  1. 运算符重载后,可以显示调用,也可以转换调用,其反汇编指令完全相同:
//显示调用
d1 > d2;
//转换调用
d1.operator>(d2);

在这里插入图片描述

  1. .* :: sizeof ?: . 注意以上5个运算符不能重载。
    PS: .*用法:
class Date
{
public://成员函数 fvoid fun(){}
private:int _year;int _month;int _day;
};
typedef void(Date::* Ptr)();//1.将 函数指针类型void(*)() 重命名为 Ptr ,并且指定在Date类内
int main()
{Ptr ptr = &Date::fun; // 2.void(*)()类型的 ptr 指向Date类内的成员函数Date test;//3.实例化test(test.*ptr)();//4. 通过ptr调用test的fun函数,就要用到.*
}

1.2 赋值运算符重载

class Date
{
public:Date(int year = 1900, 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;}//赋值运算符重载Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
private:int _year;int _month;int _day;
};
  1. 赋值运算符重载格式
  • 参数类型:const T(类型)& ->传递引用可以提高传参效率
  • 返回值类型:T(类型)& -> 返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  • 检测是否自己给自己赋值
  • 返回*this :要复合连续赋值的含义
Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
  1. 赋值运算符只能重载成类的成员函数不能重载成全局函数,否则会编译错误。
    在这里插入图片描述
    为什么呢?
    原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数

  2. 在类中,用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝(类似默认拷贝构造)。对于内置类型成员变量,是直接赋值的对于自定义类型成员变量,调用对应类的赋值运算符重载完成赋值
    在这里插入图片描述
    注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。因为默认的赋值重载实质上也是浅拷贝。

1.3 前置++和后置++重载

我们知道,无论是前置++还是后置++,其所用的运算符都是 ++。如果我们要对其重载,要如何分别实现前置++和后置++的重载呢?

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

这里也用Date类来举例:

//前置++重载:
//返回*this,也就是该类本身
Date& operator++()
{_day += 1;return *this;
}
//后置++重载:为了区分,强制加了一个int类型做区分
//后置++返回的是+1之前的值,所以要拷贝一个临时类来返回,而类本身要+1
//而temp是临时对象,因此只能以值的方式返回,不能返回引用
Date operator++(int)
{Date temp(*this);_day += 1;return temp;
}

此后所有的前置或后置类型符号的重载,都形似前置++和后置++的方式区分

2.日期类的实现

日期类的实现不仅是完整的实现其成员变量和成员函数,也要全套设计其运算符重载。

//Date.h
#pragma once
#include <iostream>
using namespace std;
class Date
{
public://打印void Print(){cout << _year << "." << _month << "." << _day<<endl;}// 获取某年某月的天数//因为该成员函数要频繁调用,所以就放在类内int GetMonthDay(int year, int month){static int a[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31 };int day = a[month];if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)){day = 29;}return day;}// 全缺省的构造函数Date(int year = 1900, int month = 1, int day = 1);// 拷贝构造函数// d2(d1)Date(const Date& d);// 赋值运算符重载// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d);// 析构函数~Date();// 日期+=天数Date& operator+=(int day);// 日期+天数Date operator+(int day);// 日期-天数Date operator-(int day);// 日期-=天数Date& operator-=(int day);// 前置++Date& operator++();// 后置++Date operator++(int);// 后置--Date operator--(int);// 前置--Date& operator--();// >运算符重载bool operator>(const Date& d);// ==运算符重载bool operator==(const Date& d);// >=运算符重载bool operator >= (const Date& d);// <运算符重载bool operator < (const Date& d);// <=运算符重载bool operator <= (const Date& d);// !=运算符重载bool operator != (const Date& d);// 日期-日期 返回天数int operator-(const Date& d);
private:int _year;int _month;int _day;
};
//Date.c
#include "Date.h"
//构造
Date::Date(int year, int month, int day )
{this->_year = year;this->_month = month;this->_day = day;
}
//拷贝构造
Date::Date(const Date& d)
{this->_year = d._year;this->_month = d._month;this->_day = d._day;
}
//赋值拷贝
Date& Date::operator=(const Date& d)
{this->_year = d._year;this->_month = d._month;this->_day = d._day;return *this;
}
//析构函数
Date::~Date()
{_year = 0;_month = 0;_day = 0;
}
// +=重构
Date& Date::operator+=(int day)
{_day += day;while(_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);//month = 12_month++;// month = 13if (_month > 12){_month = 1;_year++;}}return *this;
}
// +重构
Date Date::operator+(int day)
{Date tmp = *this;tmp += day;return tmp;
}
// -=重构
Date& Date::operator-=(int day)
{_day -= day;while (_day <= 0){_month -= 1;if (_month == 0){_month = 12;_year--;}_day += GetMonthDay(_year, _month);}return *this;
}
// -重构
Date Date::operator-(int day)
{Date tmp = *this;tmp -= day;return tmp;
}
// 前置++重构
Date& Date::operator++()
{*this = *this + 1;return *this;
}
// 后置++重构
Date Date::operator++(int)
{Date tmp = *this;*this = *this + 1;return tmp;
}
// 前置--重构
Date& Date::operator--()
{*this = *this - 1;return *this;
}
// 后置--重构
Date Date::operator--(int)
{Date tmp = *this;*this = *this - 1;return tmp;
}
// ==重构
bool Date::operator==(const Date& d)
{return d._year == _year && d._month == _month && d._day == _day;
}
// >重构
bool Date::operator>(const Date& d)
{if (_year > d._year){return true;}else if (_year == d._year && _month > d._month){return true;}else if (_month == d._month && _day > d._day){return true;}return false;
}
// <=重构
bool Date::operator<=(const Date& d)
{return !(*this > d);
}
// <重构
bool Date::operator<(const Date& d)
{if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_month == d._month && _day < d._day){return true;}return false;
}
// >=重构
bool Date::operator>=(const Date& d)
{return !(*this < d);
}
// !=重构
bool Date::operator!=(const Date& d)
{return !(*this == d);
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{Date max = *this;Date min = d;int flag = -1;if (max < min){max = d;min = *this;flag = 1;}int n = 0;while (max != min){max--;n++;}return n * flag;
}

3. const成员函数

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

class Date
{
public://const修饰成员函数//    该放在这里↓ void fun() const{}
private:int _year;int _month;int _day;Time test1;
};

在这里插入图片描述

4 取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

class Date
{
public://返回this指针也就是是Date类的地址Date* operator&(){return this;}//为了防止权限的放大,也会重载一个返回值是const修饰的指针const Date* operator&()const{return this;}
private:int _year; // 年int _month; // 月int _day; // 日
};

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

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

相关文章

代码随想录 Day17 字符串 | LC344 反转字符串 LC541 反转字符串II 卡码网54替换数字

一、反转字符串 题目&#xff1a; 力扣344&#xff1a;反转字符串 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题…

微服务相关

1. 微服务主要七个模块 中央管理平台&#xff1a;生产者、消费者注册&#xff0c;服务发现&#xff0c;服务治理&#xff0c;调用关系生产者消费者权限管理流量管理自定义传输协议序列化反序列化 2. 中央管理平台 生产者A在中央管理平台注册后&#xff0c;中央管理平台会给他…

不说成为Linux高级工程师,但成为合格的软件开发人员还是够了,一文深入浅出的精炼总结Linux核心知识点,掌握Linux的使用与高阶技巧

不说成为Linux高级工程师&#xff0c;但成为合格的软件开发人员还是够了&#xff0c;一文深入浅出的精炼总结Linux核心知识点&#xff0c;掌握Linux的使用与高阶技巧。 Linux 的学习对于一个程序员的重要性是不言而喻的。前端开发相比后端开发&#xff0c;接触 Linux 机会相对…

图像基础—图像分类

图像通常分为二值图像、灰度图像和彩色图像 图 1-3 二值图像、灰度图像和彩色图像 &#xff08;1&#xff09;二值图像 二值图像又称为黑白图像&#xff0c;图像中任何一个点非黑即白&#xff0c;要么为白色&#xff08;像素 为 255&#xff09;&#xff0c;要么为黑色&#x…

20240417,友元 FRIEND

本来要学习的吃瓜吃了一下午 目录 3.1 全局函数做友元 3.2 友元类 3.3 成员函数做友元 三&#xff0c;友元 3.1 全局函数做友元 #include<iostream> using namespace std; class Building {friend void goodGay(Building* building);//好朋友&#xff0c;可以访问…

YooAsset快速入门

文章目录 YooAsset快速入门指南&#xff1a;YooAsset学习核心要掌握的要点主要包括以下几个方面&#xff1a;基于YooAsset进行游戏资源管理的应用实例 YooAsset快速入门指南&#xff1a; YooAsset是一款专为游戏开发设计的资产管理和分发系统&#xff0c;它能够帮助开发者高效…

2024阿里云4核8G服务器租用优惠价格700元一年

阿里云4核8G服务器租用优惠价格700元1年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云优惠 aliyunfuwuqi…

怎样将excel的科学计数法设置为指数形式?

对了&#xff0c;这个问题中所谓的“指数形式”是指数学上书写的右上标的指数格式&#xff0c;能不能通过单元格设置来做这个格式的转换呢&#xff1f; 一、几个尝试 以下&#xff0c;以数字123000为例来说明。 情况1.转换成数学上的书写方式&#xff0c;如下图的样子&#x…

Easy GIS .NET GMap.Net

Easy GIS .NET & GMap.Net .NET 环境下非常简单的GIS地图开发库。 Easy GIS .NET 一个简单的GIS 桌面应用程序&#xff0c;实现了地图瓦片加载、shapefile文件和csv文件加载渲染、地图坐标系统设置及转换等等基本功能&#xff0c;非常简单易用。 Easy GIS .NET is an o…

算法之归并排序(java、python、c++)

一、JAVA 摘录归并详细分析 ✈✈✈✈✈ package algorithm.归并;import java.util.Arrays;public class Fenzhi {public static void main(String[] args) {int [] arr {8,4,1,2,7,6,3,5};mergeSort(arr, 0, arr.length-1, new int[8]);System.out.println(Arrays.toString(a…

【Godot4自学手册】第三十七节钥匙控制开门

有些日子没有更新了&#xff0c;实在是琐事缠身啊&#xff0c;今天继续开始自学Godot4&#xff0c;继续完善地宫相关功能&#xff0c;在地宫中安装第二道门&#xff0c;只有主人公拿到钥匙才能开启这扇门&#xff0c;所以我们在合适位置放置一个宝箱&#xff0c;主人公开启宝箱…

Tcpdump -r 解析pcap文件

当我们使用命令抓包后&#xff0c;想在命令行直接读取筛选怎么办&#xff1f;-r参数就支持了这个 当你使用 tcpdump 的 -r 选项读取一个之前捕获的数据包文件&#xff0c;并想要筛选指定 IP 地址和端口的包时&#xff0c;你可以在命令中直接加入过滤表达式。这些过滤表达式可以…

2024 年 Web 前端开发趋势

希腊哲学家赫拉克利特认为&#xff0c;变化是生命中唯一不变的东西。这句话适用于我们的个人生活、行业和职业领域。 尤其是前端开发领域&#xff0c;新技术、开发趋势、库和框架不断涌现&#xff0c;变化并不陌生。最近发生的一些事件正在改变开发人员构建网站和 Web 应用的方…

git 分支-变基

在git中&#xff0c;将一个分支的更改集成到另一个分支有两种主要方式&#xff1a;合并&#xff08;merge&#xff09;和变基&#xff08;rebase&#xff09;。在本节中&#xff0c;将学习什么是变基&#xff0c;如何执行变基操作&#xff0c;为什么它是一个非常强大的工具&…

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题9

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题9 信息安全管理与评估 网络系统管理 网络搭建与应用 云计算 软件测试 移动应用开发 任务书&#xff0c;赛题&#xff0c;解析等资料&#xff0c;知识点培训服务 添加博主wx&#xff1a;liuliu548…

网工交换基础——MUX VLAN

前言&#xff1a; MUX VLAN&#xff08;Multiplex VLAN&#xff0c;多复用VLAN&#xff09;提供了一种通过VLAN进行网络资源控制的机制。例如&#xff0c;在企业网络中&#xff0c;企业员工和企业客户可以访问企业的服务器。对于企业来说&#xff0c;希望企业内部员工之…

Docker安装(一)

一、安装Docker 服务器系统&#xff1a;centos 7 1.本地有docker的首先卸载本机docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \dock…

selenum操作cookie进行免登陆【爬虫必修课1】

Selenium 操作 Cookie 进行免登录 使用 Selenium 自动化登录网站是一个常见的需求。但是直接输入用户名和密码登录非常不安全,同时每次登录都需要重复这个操作也很麻烦。一个更好的方式是使用 Cookie 进行免登录。 这篇博客就来介绍如何使用 Selenium 实现 Instagram 的免登录…

Vue3从入门到实战:深度掌握组件通信(下部曲)

5.组件通信方式5-$attrs $attrs的概念&#xff1a; 在Vue中&#xff0c;$attrs 是一个特殊的属性&#xff0c;用于访问父组件向子组件传递的非特定属性。它可以让子组件轻松地获取父组件传递的属性&#xff0c;而无需在子组件中显式声明这些属性。 想象一下你有一个父组件和…

C++进阶(2)-函数

目录 一、函数提高 1.1函数默认参数 1.2函数占位参数 1.3函数重载 1.3.1函数重载概述 1.3.2函数重载注意事项 二、类和对象 2.1封装 2.1.1封装的意义 2.1.2struct和class区别 2.1.3成员属性设置为私有 2.1.4封装案例 2.2对象的初始化和清理 2.2.1构造函数和析构函数 …