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

【C++】类和对象(4) —— 类的默认成员函数(下)

目录

  • 一、赋值运算符重载
    • 1、运算符重载
    • 2、赋值运算符重载
    • 3、普通取地址运算符重载与const取地址运算符重载
      • 1、const成员函数
      • 2、取地址运算符重载

在之前我们已经学习了六个主要的默认成员函数的前三个: 类的默认成员函数(上),那么接下来将继续为大家介绍类的默认成员函数的后三个。

一、赋值运算符重载

1、运算符重载

首先我们先来学习运算符重载。运算符重载是C++中的一种强大特性,它允许程序员为自定义类型(类或结构)赋予已有的运算符新的含义,从而使这些运算符能够用于特定类型的对象操作。
我们通常使用的>、<、>=、 ++等运算符都是库里面的,它针对的仅仅只是内置类型,当运算符被⽤于类类型的对象时,C++语⾔允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使⽤运算符时,必须转换成调⽤对应运算符重载,若没有对应的运算符重载,则会编译报错。
如果我们想比较两个日期是否相等,我们不可以用==直接进行比较,因为Date是自定义类型,我们可以这样写:

 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& d1,const Date& d2) 这个函数对等号进行了重载,效果就是可以让两个日期类可以直接进行比较。
所以说,运算符重载是具有特殊名字的函数,他的名字是由operator和后⾯要定义的运算符共同构成。和其他函数⼀样,它也具有其返回类型和参数列表以及函数体。
注意:
重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元运算符有两个参数,⼆元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第⼆个参数

运算符重载函数调用方法如下图:
在这里插入图片描述
注意:
如果一个重载运算符函数是成员函数,则它的第一个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算对象少一个

#include<iostream>
using namespace std;

class Date
{
public:
   Date(int year = 1, int month = 1, int day = 1)
   {
     _year = year;
     _month month;
     _day = day;
   }
   void Print()
   {
     cout << _year << "-" << _month << "-" << _day << endl;
   }
   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(2025,1,1);
   Date d2(2025,1,2);
   //运算符重载函数可以显示调用
   d1.operator==(d2);
 }

在这里插入图片描述
在这里插入图片描述
注意:
1、.* :: sizeof ?: . 注意以上5个运算符不能重载。
2、重载操作符⾄少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: int operator + (int x , int y)
3、重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分。
在这里插入图片描述

2、赋值运算符重载

接下来我们学习赋值运算符重载,赋值运算符重载其实也是一个运算符重载,规定必须重载为成员函数。赋值运算符重载用于完成两个已经存在的对象直接的拷贝赋值。

首先我们先来看一段代码:

 class Date
 {
 public:
   Date(int year = 1, int month = 1, int day = 1)
   {
     _year = year;
     _month = month;
     _day = day;
   }
   Date(const Date& d)
   {
     cout << "Date(const Date& d)" << endl;
     _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;
   }
   void Print()
   {
     cout << _year << "-" << _month << "-" << _day << endl;
   }
 private:
   int _year;
   int _month;
   int _day;
 };
 int main()
 {
   Date d1(2025,1,1);
   Date d2(d1);
   
   Date d3 = d1;

   Date d4(2025,1,2);
   d1 = d4;
   return 0;
 }   

在上面的代码中,展示了赋值重载拷贝和拷贝构造的不同写法与调用方式。
在这里插入图片描述

赋值重载拷贝是两个已经存在的对象直接的拷贝赋值,而拷贝构造则是用于一个对象拷贝初始化给另一个要创建的对象。在上面的代码中d1,d4是已经存在的对象,而d2,d3是还未创建的对象,用d1去拷贝初始化d2,d3,属于拷贝构造。
在这里插入图片描述

注意:
上面的代码我们显式实现了一个赋值运算符重载函数,如果我们没有显式实现,编译器会⾃动⽣成⼀个默认赋值运算符重载。它对内置类型成员变量和自定义类型成员变量有着不同的处理方式:
1、对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉)。
2、对⾃定义类型成员变量会调⽤他的赋值重载函数完成赋值。

那么什么时候我们需要显式写赋值运算符重载,什么时候不需要呢?
这里我们只需要记住一句话:
如果一个类显式实现了析构并释放资源,那么他就需要显式写赋值运算符重载,否则就不需要

3、普通取地址运算符重载与const取地址运算符重载

1、const成员函数

将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后面
我们先来看一段代码:

 #include<iostream>
 using namespace std;

 class Date
 {
 public:
   Date(int year = 1, int month = 1, int day = 1)
   {
     _year = year;
     _month = month;
     _day = day;
   }
   void Print() const
   {
     cout << _year << "-" << _month << "-" << _day << endl;
   }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1(2025,1,1);
  d1.Print();

  const Date d2(2025,2,1);
  d2.Print();
  return 0;
}

const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改
在这里插入图片描述
在这里插入图片描述
同时非const成员也可以调用const成员函数。因为权限可以缩小。但是const成员不能调用非const成员函数,因为权限不可以放大(之前的章节有介绍,不懂的可以去看哦!) 关于const引用

2、取地址运算符重载

取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载。
首先我们来看一段代码:

 class Date
 {
 public:
    Date* operator&()
    {
      return this;
      //return nullptr;
    }
    const Date* operator&()const
    {
      return this;
      //return nullptr;
    }
private:
   int _year;
   int _month;
   int _day;
};

在上面的代码中展示了普通取地址运算符重载和const取地址运算符重载。
⼀般这两个函数编译器⾃动⽣成的就可以够我们⽤了,不需要去显式实现(是默认成员函数,只有特殊情况,才需要重载,比如不想别人取到该对象的地址,就可以胡乱返回一个地址。

好啦!到这里类的默认成员函数的内容我们就学完了,大家主要学习前四个(构造、析构、拷贝构造和赋值重载)。大家多多支持哦!


http://www.kler.cn/a/530520.html

相关文章:

  • LeetCode:121.买卖股票的最佳时机1
  • deepseek本地部署会遇到哪些坑
  • 无用知识之:std::initializer_list的秘密
  • Unity Shader Graph 2D - 角色身体电流覆盖效果
  • 54. 螺旋矩阵
  • Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)
  • 基于python的Kimi AI 聊天应用
  • HTML5 Canvas 与 SVG:让网页图形与动画活跃起来
  • 计算机网络 应用层 笔记1(C/S模型,P2P模型,FTP协议)
  • 搜索功能多模块展示如何实现
  • 谭浩强C语言程序设计(3) 7章
  • 第三百五十八节 JavaFX教程 - JavaFX滑块
  • Maven jar 包下载失败问题处理
  • 四、GPIO中断实现按键功能
  • dup函数和dup2函数复制文件描述符区别
  • 小程序设计和开发:如何研究同类型小程序的优点和不足。
  • 初入机器学习
  • 经典游戏红色警戒2之英语
  • MP4基础
  • EF Core与ASP.NET Core的集成
  • 知识库建设与知识管理实践对企业发展的助推作用探索
  • FreeRTOS学习 --- 任务切换
  • 网络工程师 (13)时间管理
  • 【华为OD-E卷 - 磁盘容量排序 100分(python、java、c++、js、c)】
  • IM 即时通讯系统-45-merua0oo0 IM 分布式聊天系统
  • 【Ai】DeepSeek本地部署+Page Assist图形界面