当前位置: 首页 > news >正文

类和对象(4)--《Hello C++ Wrold!》(6)--(C/C++)--赋值运算符重载,取地址和const取地址操作符重载

文章目录

  • 前言
  • 类的剩下三个默认成员函数
    • 赋值运算符重载
      • 运算符重载
      • 赋值运算符重载
      • 基本流运算符重载
    • 取地址及const取地址操作符重载
      • 关于const的引申
  • 作业部分

前言

这期的话会讲解剩余的三个默认成员函数–赋值运算符重载,取地址和const取地址操作符重载

类的剩下三个默认成员函数

赋值运算符重载

运算符重载

作用:让eg:+在自定义类型中也能使用

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator操作符(参数列表)

eg: bool operator +(const Data& a)
延申: bool ret = 1<2;这样也是可以的:ret会 = true;operator左右操作数的取哪个跟左右结合性无关哈

1.不能通过连接其他符号来创建新的操作符:比如operator@

2.重载操作符必须有一个类类型参数或者枚举类型(成员函数的话,this也算类类型参数)

3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义

作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

.*          ::        sizeof       ?:          .
(这个易忘)

注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

运算符重载是可以显示调用的

Date& operator=(const Date& d)//d1传给的是this指针,this == &d1
{
_year = d._year;
_month = d._month;
_day = d._day;
}
main函数里面 d1 = d2
//等效为d1.operator=(d2),像这种两个操作数的都是这样看的,前面那个在operator前面……
//operator=(&d1, d2)

要注意的是运算符重载和拷贝构造函数区分

d2 = d1;//属于已经存在的两个对象之间的复制拷贝的话--运算符重载函数
//不是d1(d2)
Date d2(d1)//用一个已经存在的对象初始化另一个对象--拷贝构造函数
//等价于 Date d2 = d1;

赋值运算符重载

重载时一般要做到这几点才不会错:

参数类型:const 类型&

返回值类型:类型&–不能void,不然连续赋值就遭了

返回*this

注意把自己给自己赋值那个判断一下,提高效率

注意:赋值运算符一定要重载成成员函数,不然系统还会自己再生成一个

Date& operator=(const Date& d){if(this != &d)//这个操作还行{_year = d._year;_month = d._month;_day = d._day;}return *this;}

系统自动生成的赋值重载函数:(跟拷贝构造的这个规则差不多)

1.内置类型成员进行浅拷贝

2.自定义类型成员会去调用他的赋值重载

基本流运算符重载

printf处理不了自定义类型的东西,但是基本流运算符的使用者cin,cout可以

cin(类型是:istream)和cout(类型是:ostream)支持自动识别类型的原因:

1.内置类型是因为库里面实现了

2.支持自定义类型是因为自己写的函数重载

(这个的函数重载的例子也在下面的日期类实现那里)

注意:基本运算符不能写成成员函数

可以显示调用:

cout<<d1;--operator<<(cout,d1);

基本流运算符不能写成成员函数的原因:

要写成成员函数的话,对象要占用operator的左操作数才行(因为this指针会去悄咪咪的占了),写出来就会是下面这个样子,不符合使用习惯

void operator<<(ostream& out);

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

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

关于const的引申

1.也是有权限缩小,平移,扩大的那个问题

const int a = 10;
int*pb = &a;//这个就算权限扩大了,是不行的

2.成员函数后面加const之后,普通的对象和const过了的对象都可以调用

成员函数加const:
void Print()const这样加const才表示让this指针指向的对象不能被修改

总结对第二点:

只要成员函数内部不修改成员变量,都应该加const,这样const对象和普通对象都可以调用

const对象:比如:const d1(2025,5,7);
在调用时:d2.Print();相当于d2.Print(&d2);this指向d2,所以有了上面那个说法

作业部分

设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?(B)
C c;
int main()
{A a;B b;static D d;return 0;
}
A.D B A C
B.B A D C
C.C D B A
D.A B D C
构造顺序是按照语句的顺序进行构造,析构是按照构造的相反顺序进行析构
然后因为有static,所以d的生存周期变了,但是没C长

在这里插入图片描述

下列关于赋值运算符“=”重载的叙述中,正确的是(A)
A.赋值运算符只能作为类的成员函数重载//理解
B.默认的赋值运算符实现了“深层复制”功能
C.重载的赋值运算符函数有两个本类对象作为形参//这里的形参指的是()里面的
D.如果己经定义了复制拷贝构造函数,就不能重载赋值运算符

在这里插入图片描述

&作取地址和引用的区分:
在描述类型时的&才是引用
日期类的部分实现
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month)
{static int daysArr[13] = { 0, 31, 28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31 };//避免了每次都需要创建//if (((year % 4 == 0 && year % 100 != 0) ||//       (year % 400 == 0)) && month == 2)if (month == 2 && ((year % 4 == 0 && year % 100 != 0) ||(year % 400 == 0)))//这样更好{return 29;}else{return daysArr[month];}
}// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);// 拷贝构造函数
// d2(d1)
Date(const Date& d);// 赋值运算符重载
Date& operator=(const Date& d);// 析构函数
~Date();Date& Date::operator+=(int day)
{if(day<0)   return *this-=-day;//防止day是负数;这个-=要自己实现!_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13)//这里不是用的while{++_year;_month = 1;}}return *this;
}Date Date::operator+(int day)
{Date tmp(*this);tmp += day;//就像这样,用到之前已经实现了的部分来简化return tmp;// 前置++
Date& operator++()
{*this += 1;return *this;
}// 后置++
Date Date::operator++(int)
{Date tmp = *this;*this += 1;return tmp;
}// 日期-日期 返回天数
int operator-(const Date& d) const
{Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1;//表明那个d才是大的}int n = 0;while (min != max){++min;++n;}return n * flag;//flag的巧用,比if来搞好
}int GetYear()
{return _year;//这种方法能让私有的能拿出去
}private:
int _year;
int _month;
int _day;
};ostream& operator<<(ostream& out, const Date& d)
//不能改成 const ostream& out
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
//这里不能这样搞,除非设置成友元(像上面写的那样)
//对象的成员函数不是只能用成员变量用return out;
}istream& operator>>(istream& in, Date& d)//注意这两个的类型!
{int year, month, day;in >> year >> month >> day;//感觉还是上面那种读法好些if (month > 0 && month < 13&& day > 0 && day <= d.GetMonthDay(year, month)){d._year = year;d._month = month;d._day = day;}else{cout << "非法日期" << endl;assert(false);//这后面的操作是防止用户输入错误日期}

注意:前置不用加int,后置要加int这个是规定,不能颠倒,参数也不能换成其他类型,让这两个构成重载

在上面的基础上,用eg:d1++;那么编译器就会调用d1.operator(0)//调用时这的int是0

注意:前置返回++之前的对象,后置返回++之后的对象(用来实现前后置效果)

注意:对于内置类型来说,前置和后置的代价差不多,可以忽略不计;但是对自定义类型来说,前置比后置代价小不少(后置需要多构造一个临时对象),平时应该多用前置的

相关文章:

  • 替代云数据库的本地方案:MySQL+phpMyAdmin的远程管理与跨网络访问技术
  • CSS3过渡
  • CSR矩阵 矩阵压缩
  • VSCode推出开源Github Copilot:AI编程新纪元
  • html主题切换小demo
  • VisionPro_连接相机
  • labview实现LED流水灯的第二种方法
  • 机器人坐标系标定
  • spring boot 实现resp视频推流
  • 数据结构:绪论之时间复杂度与空间复杂度
  • OceanBase数据库全面指南(函数篇)函数速查表
  • 基于cornerstone3D的dicom影像浏览器 第二十一章 显示DICOM TAGS
  • 先更新数据库,再删除缓存的cache aside策略
  • 性能测试、压力测试、负载测试如何区分
  • 工业 / 农业 / AR 场景怎么选?Stereolabs ZED 双目3D相机型号对比与选型建议
  • 【Django Serializer】一篇文章详解 Django 序列化器
  • WooCommerce缓存教程 – 如何防止缓存破坏你的WooCommerce网站?
  • [免费]微信小程序宠物医院管理系统(uni-app+SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
  • 初步尝试AI应用开发平台——Dify的本地部署和应用开发
  • 优化 CRM 架构,解锁企业竞争力密码
  • 网站设计书籍/网址网域ip地址查询
  • 做网站 异地域名/个人网站设计作品
  • 浙江华企网站做的咋样/世界新闻最新消息
  • 焦作建网站/东莞排名优化团队
  • 科技网站建设分析/市场营销渠道
  • 我的南京网站/厦门网站制作