【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,一经查实,立即删除!

相关文章

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

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

知识图谱驱动的深度推理: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; …

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Python酷库之旅-第三方库Pandas(010)

目录 一、用法精讲 22、pandas.read_hdf函数 22-1、语法 22-2、参数 22-3、功能 22-4、返回值 22-5、说明 22-6、用法 22-6-1、数据准备 22-6-2、代码示例 22-6-3、结果输出 23、pandas.HDFStore.put方法 23-1、语法 23-2、参数 23-3、功能 23-4、返回值 23-5…

【Linux】线程(轻量级进程)

目录 一、线程概念 二、线程特性 2.1 进程更加轻量化 2.2 线程的优点 2.3 线程的缺点 2.4 线程的异常 2.5 线程用途 三、进程和线程 四、线程控制 4.1 包含线程的编译链接 4.2 创建线程 4.3 获得线程自身的ID 4.4 线程终止 4.5 线程等待 4.6 线程分离 4.6 线程…

恢复出厂设置后如何从 iPhone 恢复数据

在 iPhone 恢复出厂设置后&#xff0c;所有数据都会被删除&#xff0c;并且 iPhone 将恢复到原始出厂设置&#xff0c;这意味着您的所有 iPhone 数据&#xff0c;包括照片、视频、联系人和应用程序都将消失。 幸运的是&#xff0c;如果您有备份可以恢复&#xff0c;这并不一定…

处理训练和验证数据集

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️如遇文章付费&#xff0c;可先看…

名企面试必问30题(二十五)—— 你手上还有没有其他的offer?

1.思路 主要考察你的意向度、时长竞争力和薪资空间&#xff0c;如果回答有offer&#xff0c;需要准备面试官追问还在考虑的原因。 2.参考解答 方式一&#xff1a; “目前我还没有其他的 offer。我一直非常专注于寻找真正适合我&#xff0c;并且能让我充分发挥自身能力和潜力的工…

spring boot(学习笔记第十二课)

spring boot(学习笔记第十二课) Spring Security内存认证&#xff0c;自定义认证表单 学习内容&#xff1a; Spring Security内存认证自定义认证表单 1. Spring Security内存认证 首先开始最简单的模式&#xff0c;内存认证。 加入spring security的依赖。<dependency>…

JDBC的基本认识

前提 在了解和学习JDBC之前&#xff0c;大家 已经学习过 java语言 和数据库的基本知识了&#xff0c;今天这篇博客的核心&#xff0c;就是告诉大家 &#xff0c;jdbc 是连接java编译器和数据库&#xff0c;是使用java对数据库进行操作的。 正文 JDBC简介 概念 JDBC的本质 1…

【软件分享】气象绘图软件Panoply

气象是大气中的物理现象&#xff0c;气象要素则是表明大气物理状况的要素&#xff0c;主要的气象要素有降水、风、气压、湿度等。为了研究气象要素在空间上的分布和运动状况&#xff0c;我们需要对气象要素进行空间上进行可视化&#xff0c;这个时候就需要气象领域的一些的绘图…