【C++】类和对象(中)--下篇

在这里插入图片描述
个人主页~
类和对象上
类和对象中-上篇


类和对象

  • 五、赋值运算符重载
    • 1、运算符重载
    • 2、赋值运算符重载
    • 3、前置++和后置++重载
  • 六、const成员
  • 七、日期类的实现
    • Date.h
    • Date.cpp
    • test.cpp
      • test1测试结果
      • test2测试结果
      • test3测试结果
      • test4测试结果
      • test5测试结果
      • test6测试结果
      • test7测试结果
  • 八、关于取地址和const取地址操作符重载

五、赋值运算符重载

1、运算符重载

运算符重载是具有特殊函数名的函数,是C++为了增强代码可读性而引入的

operator sign(parameter);

operator为关键字,sign就是需要重载的运算符符号,parameter为参数(可以为多个)

注意事项:

不能通过连接其他符号来创建新的操作符

重载操作符至少有一个类类型参数

用于内置类型之间的运算符含义不改变,编译器会自动检测使用运算符的类型是什么,从而选择是否改变运算符含义

类成员函数重载时有一个隐藏的参数this

不能重载的五个运算符
.*
::
sizeof
?:
.

重载一个==

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

但定义一个全局函数需要成员函数公有,所以我们直接定义在类内,保证其封装性

//……类内
bool operator==(const Date& d2)
{return _year == d2._year&& _month == d2._month&& _day == d2._day;
}
//……

2、赋值运算符重载

(1)格式
参数类型 const name& 引用传参

返回值类型 name& 返回引用

检测是否自己给自己赋值

返回*this

(2)赋值运算符的重载
赋值运算符只能重载成类的成员函数不能重载成全局函数

赋值运算符如果不显式实现,编译器会生成一个默认的,此时再在外边实现一个全局的赋值运算符重载,就会发生冲突

class Date
{
public:Date(int year, int month, int day){_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;
};

(3)用户没有显式实现时,编译器会生成一个默认赋值运算符重载,然后值拷贝,内置成员直接赋值,自定义成员需要调用对应类的赋值运算符重载完成赋值

(4)有了值拷贝我们就一定要说说深拷贝,在Date类这样的类中不需要我们自己实现,而在Stack这样的类中就需要显式实现,进行资源管理

拿出我们的老演员栈:

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

在这里插入图片描述
调试后发现又是析构函数这里出了问题,原因同拷贝构造函数:因为编译器自动生成的拷贝构造函数是值拷贝,所以在生成s2时,s2中的指针a指向的数组与s1中的指针指向的数组相同,在程序结束时,调用析构函数释放了s2,对应的这块数组空间也被释放,然后调用析构函数释放s1,已经被释放的空间不能被再次释放,所以出现了这样的错误,所以我们需要自己显式定义一个拷贝构造函数

3、前置++和后置++重载

我们先来复习一下前置++和后置++的区别,在仅自加时也就是在n++为一条语句时没有区别,在赋值时,前置++是先+1后赋值,后置++是先赋值再+1

如果我们想要++重载,那么就是定义operator++,分不出为前置还是后置,所以我们规定operator++为前置++operator++(int)为后置++

class Date
{
public:Date(int year = 1970, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date& operator++(){*this += 1;return *this;}Date operator++(int){Date tmp(*this);*this += 1;return tmp;}//所以后置++会使用空间拷贝,效率比前置++低void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{Date d;Date d1(2000,1,1);d = d1++;d.Print();d1.Print();d = ++d1;d.Print();d1.Print();return 0;
}

在这里插入图片描述

六、const成员

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

因为参数为隐藏的,所以我们的方法如下:

void Date::Print() const
{cout << _year << "/" << _month << "/" << _day << endl;
}

相当于

void Date::Print(const Date* this) 
{cout << _year << "/" << _month << "/" << _day << endl;
}

注意:

const对象不能调用非const成员函数

非const对象能调用const成员函数

const成员函数内不能调用其他非const成员函数

非const成员函数内能调用其他const成员函数

七、日期类的实现

Date.h

#pragma once
#include <iostream>
using namespace std;class Date
{
public:int GetMonthDay(int year, int month);Date(int year = 1970, int month = 1, int day = 1);Date(const Date& d);~Date();Date& operator=(const Date& d);Date& operator+=(int day);Date& operator-=(int day);Date& operator++();Date operator++(int);Date& operator--();Date operator--(int);Date operator+(int day);Date operator-(int day);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);void Print() const;
private:int _year;int _month;int _day;
};

Date.cpp

#define _CRT_SECURE_NO_WARNINGS#include "Date.h"int Date::GetMonthDay(int year, int month)
{const static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))){return 29;}return days[month];
}Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;if (month < 1 || month > 12|| day < 1 || day > GetMonthDay(year, month)){cout << "非法日期" << endl;exit(-1);}
}Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}Date::~Date()
{_year = _month = _day = 0;
}
//日期类的析构函数其实没必要写
Date& Date::operator=(const Date& d)
{if(this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}Date& Date::operator+=(int day)
{if (day < 0){return *this -= (-day);}//复用-=_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13){++_year;_month = 1;}}return *this;
}Date& Date::operator-=(int day)
{if (day < 0){return *this += (-day);}//复用+=_day -= day;while (_day <= 0){--_month;if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}Date& Date::operator++()
{*this += 1;return *this;
}Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}Date& Date::operator--()
{*this -= 1;return *this;
}Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return tmp;
}bool Date::operator==(const Date& d)
{return _year == d._year&& _month == d._month&& _day == d._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 (_year == d._year && _month == d._month && _day < d._day){return true;}else{return false;}
}// d1 <= d2
bool Date::operator<=(const Date& d)
{return *this < d || *this == d;
}bool Date::operator>(const Date& d)
{return !(*this <= d);
}bool Date::operator>=(const Date& d)
{return !(*this < d);
}bool Date::operator!=(const Date& d)
{return !(*this == d);
}int Date::operator-(const Date& d)
{
//假设左大右小,此时标识符flag为1Date max = *this;Date min = d;int flag = 1;
//如果左小右大,则置换后置标识符flag为-1if (*this < d){max = d;min = *this;flag = -1;}
//算出大的与小的之间的天数int n = 0;while (min != max){++min;++n;}
//返回与标识符flag的乘积return n * flag;
}void Date::Print() const
{cout << _year << "/" << _month << "/" << _day << endl;
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS#include "Date.h"
//初始化
void test1()
{Date d1(2000, 1, 1);d1.Print();Date d2;d2.Print();Date d3 = Date(d1);d3.Print();
}
//++
void test2()
{Date d1(2001, 2, 28);Date d2 = d1++;Date d3 = ++d1;
}
//+ -
void test3()
{Date d1(2000, 1, 1);Date d2 = d1 + 20000;Date d3 = d1 - 20000;
}
//--
void test4()
{Date d1(2000, 3, 1);Date d2 = d1--;Date d3 = --d1;
}
//+= -=
void test5()
{Date d1(2000, 1, 1);d1 += 20000;Date d2;d2 -= 20000;
}
//日期-日期
void test6()
{Date d1(2000, 1, 1);Date d2;int a = d1 - d2;
}
//=
void test7()
{Date d1(2000, 1, 1);Date d2;d2 = d1;
}
int main()
{//test1();//test2();//test3();//test4();//test5();//test6();//test7();return 0;
}

test1测试结果

在这里插入图片描述
构造和拷贝构造函数正常

test2测试结果

在这里插入图片描述
在这里插入图片描述
前置后置++都正常

test3测试结果

在这里插入图片描述

在这里插入图片描述

+、 - 不改变原来的值,正常

test4测试结果

在这里插入图片描述

在这里插入图片描述
前置后置- -正常

test5测试结果

在这里插入图片描述
-= +=改变原来的数,正常

test6测试结果

在这里插入图片描述
日期减日期为整数正常

test7测试结果

在这里插入图片描述

=赋值正常

全部正常

八、关于取地址和const取地址操作符重载

&
const …… &
这两个一般不用重新定义,编译器会默认生成,如果有别的用途,可以显式定义重载


今日分享结束~

在这里插入图片描述

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

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

相关文章

Spring Boot 事件监听机制工作原理

前言&#xff1a; 我们知道在 Spring 、Spring Boot 的启动源码中都大量的使用了事件监听机制&#xff0c;也就是我们说的的监听器&#xff0c;监听器的实现基于观察者模式&#xff0c;也就是我们所说的发布订阅模式&#xff0c;这种模式可以在一定程度上实现代码的解耦&#…

SAP FICO自定义权限对象及自定义作业创建

设置的通用说明 要求设置税收分组权限&#xff0c;自定义权限对象&#xff1a;Z_SSFZ 执行按钮权限控制&#xff1a;权限对象Z_SSFZ 字段名&#xff1a;ZSSFZ对应维护税收分组 字段名&#xff1a;ZACTVT01 01&#xff1a;付款银行信息维护 02&#xff1a;员工基本信息维护…

Ant-Vue——modal对话框

在Vue3的项目里&#xff0c;组件库用的是Ant-design 3.2版本 修改样式 需求是需要修改原生的 modal 样式 如果直接用类名 .ant-modal-body 去修改样式&#xff0c;会发现无法修改。因为默认不支持修改高度和外边距padding 所以需要&#xff1a;先通过 挂载元素 再css穿透/de…

知识图谱驱动的深度推理:ToG算法的创新与应用

LLMs通过预训练技术在大量文本语料库上生成连贯且符合上下文的响应。然而&#xff0c;面对需要复杂知识推理的任务时&#xff0c;它们存在明显的局限性。这些问题包括对超出预训练阶段的专业知识的准确回答失败&#xff0c;以及缺乏责任性、可解释性和透明度。为了解决这些问题…

伦敦银交易平台价格的突破成不成功?这点很重要!

在伦敦银交易中&#xff0c;当银价出现突破的时候&#xff0c;也正是引起很多投资者关注的时候。一旦银价出现突破&#xff0c;很可能是新行情的开端。但是做过突破交易&#xff0c;有相关经验的朋友会发现&#xff0c;自己在伦敦银交易平台做突破的时候&#xff0c;也并不是每…

【QT】多元素控件

多元素控件 多元素控件1. List Widget2. Table Widget3. Tree Widget 多元素控件 Qt 中提供的多元素控件有: QListWidgetQListViewQTableWidgetQTableViewQTreeWidgetQTreeView xxWidget 和 xxView 之间的区别&#xff0c;以 QTableWidget 和 QTableView 为例&#xff1a; …

怎麼解決代理伺服器中的網路延遲問題-okeyproxy

使用代理伺服器時&#xff0c;不可避免地會遇到網路延遲的問題。本文將深入探討代理伺服器中的網路延遲問題&#xff0c;並提出一些解決方案。 什麼是網路延遲&#xff1f; 網路延遲指的是數據從一個點傳輸到另一個點所需的時間&#xff0c;它通常以毫秒&#xff08;ms&#…

数据结构--二叉树相关题2(OJ)

1.比较对称二叉树&#xff08;镜像二叉树&#xff09; 二叉树相关题1中第二题的变形题。先去看1哦&#xff01; 左子树和右子树比较 bool _isSymmetric(struct TreeNode* p, struct TreeNode* q) {if (p NULL && q NULL)return true;//如果两个都为空则是相等的if …

01前端导入

【一】前后端介绍 1.前端&#xff1a;通俗的说就是用户所看到的页面&#xff0c;通过浏览器渲染出来的页面 2.后端&#xff1a;就是对数据进行逻辑校验和加密等操作&#xff0c;用户看不到的操作 【二】浏览器访问地址全流程 1.输入网址--》https://www.baidu.com/域名 2.解…

AI产品经理一篇读透知识图谱(万字深度好文)

1、知识图谱技术综述 知识图谱技术是人工智能技术的组成部分&#xff0c;其强大的语义处理和互联组织能力&#xff0c;为智能化信息应用提供了基础。以下内容涵盖了基本定义与架构、代表性知识图谱库、构建技术、开源库和典型应用。 引言 随着互联网的发展&#xff0c;网络数…

查询进程并且杀死

使用命令行工具 Tasklist 和 Taskkill 来查询和删除&#xff08;终止&#xff09;进程。以下是详细步骤&#xff1a; 查询进程 打开命令提示符&#xff08;以管理员身份运行以获得所有权限&#xff09;。 使用 tasklist 命令列出所有正在运行的进程&#xff1a; tasklist这将…

抖音短视频矩阵系统全攻略:从入门到精通

在数字化时代&#xff0c;短视频已成为连接用户与内容的桥梁。抖音作为短视频领域的领军平台&#xff0c;其影响力不容小觑。抖音短视频矩阵系统的构建和管理&#xff0c;对于希望在这个平台上取得成功的创作者和品牌来说至关重要。本文将提供一份全面的攻略&#xff0c;从入门…

Python|Pyppeteer实现获取携程网“指定城市”特价机票(25)

前言 本文是该专栏的第25篇,结合优质项目案例持续分享Pyppeteer的干货知识,记得关注。 本文以携程的城市特价机票为例子,通过pyppeteer登录携程,然后指定两个目标城市(出发城市,目的地到达城市),获取这两个城市之间的特价机票。 需要注意的是,对pyppeteer不太熟悉的…

Qt篇——QLabel固定尺寸的情况下让字体大小自适应并自动换行以完整显示

当文字较少时&#xff0c;默认字体大小为16&#xff1b;当文字内容较多时&#xff0c;自动换行并缩小字体。 举例&#xff1a; 字体较少时 字体较多时 思路&#xff1a; 设置自动换行属性 setWordWrap&#xff1b;通过QFontMetrics计算文字字体要多大、显示多少行才不会超过…

做外贸干一行爱一行,还是干一行厌一行?

记得年轻的时候&#xff0c;每每和同龄人不同行业聊天的时候&#xff0c;大家普遍的感觉就是&#xff1a;自己这一行太苦了&#xff0c;以后有孩子了干什么都不能让他做自己这一行。 和在银行上班的同学聊天&#xff0c;他们最大的苦恼是需要每天开发客户&#xff0c; 让客户在…

【0295】Posgres内核 dynahash table 之 hash_search 实现原理(2)

相关文章: 【0294】Postgres内核 dynahash 之 hash_search 实现原理(1) 0. 前言 在【0294】Postgres内核 dynahash 之 hash_search 实现原理(1) 一文中,从Postgres内核源码角度详细讲解了dynamic hash table中 hash search 的实现原理。 具体内容: 如何确定segment位置…

8、开发与大模型对话的独立语音设备

一、设计原理 该系统的核心部分主要由ESP32-WROVER开发板和ESP32-CAM摄像头、MAX9814麦克风放大器模块、MAX98357功放、声音传感器和SU-03T语音识别芯片构成。通过使用ESP32-WROVER开发板,用户可以实现通过语音与ai进行交互并进行人脸识别。 系统中,从外部输入电源中获取电源…

一手洞悉泰国slot线上游戏投放本土网盟CPI计费广告优势

一手洞悉泰国slot线上游戏投放本土网盟CPI计费广告优势 ​在泰国这个拥有独特文化背景和审美观念的国家&#xff0c;Slots游戏以其丰富的玩法和刺激的体验迅速赢得了玩家们的喜爱。然而&#xff0c;要在竞争激烈的市场中脱颖而出&#xff0c;有效的推广策略显得尤为重要。本土…

HTTP有哪些失败原因?怎么处理?

在网络通信中&#xff0c;HTTP&#xff08;超文本传输协议&#xff09;是最常用的协议之一&#xff0c;它支持万维网上的数据交换。然而&#xff0c;在使用HTTP进行数据传输时&#xff0c;可能会遇到各种失败的情况。本文将探讨HTTP请求失败的常见原因&#xff0c;并提供相应的…

【Excel操作】Python Pandas判断Excel单元格中数值是否为空

判断Excel单元格中数值是为空&#xff0c;主要有下面两种方法&#xff1a; 1. pandas.isnull 2. pandas.isna判断Excel不为空&#xff0c;也有下面两种方法&#xff1a; 1. pandas.notna 2. pandas.notnull假设有这样一张Excel的表格 我们来识别出为空的单元格 import panda…