【C++】类与对象(三)—运算符重载|const成员函数|取地址及const取地址操作符重载

在这里插入图片描述

前言
运算符重载,自增自减运算符重载,const成员函数,取地址及const取地址操作符重载


文章目录

  • 一、运算符重载
    • 自增和自减运算符重载
  • 二、const 成员函数
  • 三、取地址及const取地址操作符重载(了解即可)

一、运算符重载

运算符重载允许重新定义类对象的运算符行为。通过运算符重载,你可以使自定义类型的对象与内置类型一样,使用各种运算符进行操作,从而提高代码的可读性和灵活性。

语法:

//函数名:关键字operator后面接需要重载的运算符符号。
//函数原型:返回值类型 operator操作符(参数列表)
ReturnType operator+(参数) {// 重载的 + 运算符的实现// 返回类型可以是任何合适的类型}

运算符重载可以被重载成类的成员函数,也可以被重载成全局函数。重载成员函数形式的赋值运算符在使用时通过成员访问方式调用,而重载全局函数形式的赋值运算符则直接通过函数名调用。
1. 成员函数形式:

class MyClass {
public:// 成员函数形式的赋值运算符重载MyClass& operator=(const MyClass& other) {// 实现赋值操作// 返回当前对象的引用if (this != &other) {// 实现赋值操作,例如深拷贝资源}return *this;}
};// 调用
MyClass obj1, obj2;
obj1 = obj2;

在成员函数形式中,运算符重载是通过对象的成员访问方式调用的。左侧的对象(obj1)成为调用对象,右侧的对象(obj2)成为参数传递给成员函数。


2. 全局函数形式:
在全局函数的形式下,函数的参数中不会隐含this指针,因此要传两个参数。

class MyClass {// MyClass 的声明
};// 全局函数形式的赋值运算符重载
MyClass& operator=(MyClass& obj1, const MyClass& obj2) {// 实现赋值操作// 返回第一个对象的引用if (&obj1 != &obj2) {// 实现赋值操作,例如深拷贝资源}return obj1;
}// 调用
MyClass obj1, obj2;
obj1 = obj2;

在全局函数形式中,运算符重载是通过函数名直接调用的。左侧的对象(obj1)成为函数的第一个参数,右侧的对象(obj2)成为函数的第二个参数。


注意:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  • 作为成员函数重载时,第一个参数为隐藏的this
  • .* :: sizeof ?: . 这5个运算符不能重载。.* 用于访问类成员指针的操作符。

自增和自减运算符重载

前置和后置自增自减运算符的区分是通过参数列表的一个标识符来实现的。具体来说,前置版本没有任何参数,而后置版本有一个额外的(但不使用)int参数。

这里以自增为例:

重载前置自增运算符ReturnType operator++(){}重载后置自增运算符ReturnType operator++(int){}

前置和后置自增的实现:

  • 前置自增运算符重载:

    class MyClass {
    private:int value;
    public:// 重载前置自增运算符MyClass& operator++() {++value;return *this;}
    };
    
  • 后置自增运算符重载:

    class MyClass {
    private:int value;
    public:// 重载后置自增运算符MyClass operator++(int) {MyClass temp = *this; // 保存原始值++value;             // 执行自增操作return temp;         // 返回原始值}
    };
    

注意:

  • 前置自增运算符返回引用,使得可以对同一对象连续进行自增操作。
  • 后置自增运算符通过返回原始值的副本,再执行自增操作,以允许保留原始值。

二、const 成员函数

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

以日期类为例:
我们创建一个对象,同时加const修饰,变成常量对象。

class Date {
private:int _year;int _month;int _day;
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print() {cout << _year << "/" << _month << "/" << _day << endl;}
};int main() {//d1 被声明为常量对象,不可修改const Date d1(2024, 1, 31);//报错:“void Date::Print(void)”: 不能将“this”指针从“const Date”转换为“Date &”//d1.Print(); return 0;
}

当我们调用成员函数Print()时,编译器会报错,这是因为在通过对象调用成员函数时,this指针被隐式传参,d1是只读不可修改,但在Print()又没有办法对this指针进行限制,所以会出现权限放大的情况。权限只可以平移,缩小,但是不能放大。

//Date成员函数
void Print() {cout << _year << "/" << _month << "/" << _day << endl;}Date d1(2024, 1, 31);
//d1 是可读可修改,在Print()内同样是可读可修改的,这是权限平移
d1.Print();//---------------------------------------------------------------------void Print(const int a) {cout << _year << "/" << _month << "/" << _day << endl;}Date d1(2024, 1, 31);int a = 5;
//在Print()中a不可被修改,这是权限缩小
d1.Print(a);

所以提出了const成员函数的概念。在函数名后加const实际上限制了this指针。

//在函数名后面加上const
void Print() const {cout << _year << "/" << _month << "/" << _day << endl;}
//实际上是对this的修饰
void Print(/*const Date* this*/) {cout << _year << "/" << _month << "/" << _day << endl;}

另外,如果一个类有两个版本的成员函数,一个是const版本,一个是非const版本,它们可以根据需要被const和非const对象调用。这实际上是函数重载


思考这些问题:

  1. const对象可以调用非const成员函数吗?
  2. 非const对象可以调用const成员函数吗?
  3. const成员函数内可以调用其它的非const成员函数吗?
  4. 非const成员函数内可以调用其它的const成员函数吗?

  1. const对象可以调用非const成员函数吗?

    • 不可以。const 对象只能调用 const 成员函数,因为 const 对象的目的是确保对象的状态不被修改。调用非 const 成员函数会导致编译错误。
  2. 非const对象可以调用const成员函数吗?

    • 是的。非 const 对象可以调用 const 成员函数。这是因为 const 成员函数对对象的状态有只读的访问权限,不会修改对象的成员变量。因此,非 const 对象可以安全地调用 const 成员函数。
  3. const成员函数内可以调用其他的非const成员函数吗?

    • 是的。在 const 成员函数内部,可以调用其他非 const 成员函数,只要这些非 const 成员函数不会修改对象的成员变量。这是因为 const 成员函数对对象的状态有限制,但它可以调用其他不会修改状态的函数。
  4. 非const成员函数内可以调用其他的const成员函数吗?

    • 是的。非 const 成员函数内部可以调用 const 成员函数,因为非 const 成员函数对对象的状态没有限制,可以进行读写操作。因此,非 const 成员函数可以调用 const 成员函数,而不会导致问题。

三、取地址及const取地址操作符重载(了解即可)

Date* operator&(){return this;
}const Date* operator&()const{return this;
}

取地址及const取地址操作符重载也是默认成员函数,不需要显式提供,编译器可以自己生成。

class Date{
private:int _year;int _month;int _day;
public:Date(int year, int month, int day) {_year = year;_month = month;_day = day;}Date* operator&(){return this;}const Date* operator&()const{return this;}
};int main() {Date a(2024, 1, 31);const Date b(2024, 1, 3);cout << &a << endl;cout << &b << endl;return 0;
}

在这里插入图片描述


在这里插入图片描述
如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。

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

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

相关文章

【微服务】skywalking自定义链路追踪与日志采集

目录 一、前言 二、自定义链路追踪简介 2.1 自定义链路追踪应用场景 2.2 链路追踪几个关键概念 三、skywalking 自定义链路追踪实现 3.1 环境准备 3.2 集成过程 3.2.1 导入核心依赖 3.2.2 几个常用注解 3.2.3 方法集成 3.2.4 上报追踪信息 四、skywalking 自定义日志…

一文讲完Jetpack常用修饰符

Jetpack Compose系列(4) - 修饰符 修饰符 Modifier&#xff0c;即JetpackCompose中的修饰符&#xff0c;可以用来修饰以下内容&#xff1a; 更改可组合项的大小、布局、行为和外观 添加信息&#xff0c;如无障碍标签 处理用户输入 添加高级互动&#xff0c;如使元素可…

2024年【低压电工】复审考试及低压电工作业考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 低压电工复审考试参考答案及低压电工考试试题解析是安全生产模拟考试一点通题库老师及低压电工操作证已考过的学员汇总&#xff0c;相对有效帮助低压电工作业考试题库学员顺利通过考试。 1、【单选题】()是保证电气作…

第二十四天| 77. 组合

Leetcode 77. 组合 题目链接&#xff1a;77 组合 题干&#xff1a;给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。你可以按 任何顺序 返回答案。 思考&#xff1a;回溯法。把回溯法的搜索过程抽象为树形结构。 每次从集合中选取元素&#xff0…

【开源】基于JAVA+Vue+SpringBoot的河南软件客服系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统管理人员2.2 业务操作人员 三、系统展示四、核心代码4.1 查询客户4.2 新增客户跟进情况4.3 查询客户历史4.4 新增服务派单4.5 新增客户服务费 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的河…

【Python小游戏】五子棋小游戏(完整代码)

文章目录 写在前面Tkinter简介五子棋小游戏游戏介绍程序设计运行结果注意事项写在后面写在前面 本期内容:基于tkinter开发一个五子棋小游戏 实验环境 python3.11及以上pycharmtkinterTkinter简介 Tkinter是Python中最常用的图形用户界面(GUI)库之一,用于创建窗口、对话框…

Map和Set的封装

目录 一、底层原理 二、红黑树的节点 三、仿函数 四、迭代器 4.1、迭代器的定义&#xff1a; 4.2、*:解引用操作 4.3、->:成员访问操作符 4.4、!、 4.5、迭代器的&#xff1a; 4.6、迭代器的-- 五、Map 六、Set 七、红黑树源码 一、底层原理 我们要知道&#…

vue 阿里图标库引入分享

上篇文章分享了element-ui icon 组件的实现原理&#xff0c;文章当中有涉及到了阿里图标库的使用&#xff0c;当时未做详细使用说明&#xff0c;此篇文章是对上篇文章的补充哈。 本篇文章主要分为以下两部分&#xff1a; 一、阿里图标库使用 1.1 阿里图标库地址&#xff1a;…

029 命令行传递参数

1.循环输出args字符串数组 public class D001 {public static void main(String[] args) {for (String arg : args) {System.out.println(arg);}} } 2.找打这个类的路径&#xff0c;打开cmd cmd C:\Users\Admin\IdeaProjects\JavaSE学习之路\scanner\src\com\yxm\demo 3. 编译…

华为机考入门python3--(7)牛客7-取近似值

分类&#xff1a;数字 知识点&#xff1a; str转float float(str) 向上取整 math.ceil(float_num) 向下取整 math.floor(float_num) 题目来自【牛客】 import math def round_to_int(float_num): # 如果小数点后的数值大于等于0.5&#xff0c;则向上取整&#xf…

Unity 读取指定目录所占内存大小

public static class TxxTool{#region 读取文件大小private static List<string> DirList new List<string>();public static long GetFileSize(string path){DirList new List<string>();DirList.Add(path);GetAllDirecotries(path);long fileSize 0;for…

c语言--求第n个斐波那契数列(递归、迭代)

目录 一、概念二、用迭代求第n个斐波那契数1.分析2.完整代码3.运行结果4.如果求第50个斐波那契数呢&#xff1f;看看会怎么样。4.1运行结果&#xff1a;4.2画图解释 三、用迭代的方式求第n个斐波那契数列1.分析2.完整代码3.运行结果4.求第50个斐波那契数4.1运行结果4.2运行结果…