C++入门《类和对象》之《运算符重载》详解|成员函数重载/非成员函数重载

C++ 中,运算符重载是一种特殊的函数,它允许程序员为自定义的数据类型(如类和结构体)重新定义运算符的行为,使得这些运算符能够像处理内置数据类型一样处理自定义类型的数据。下面将从多个方面详细讲解 C++ 里的运算符重载。

基本语法 

运算符重载的本质是定义一个函数,其一般形式如下:

返回类型 operator运算符(参数列表) {// 函数体
}

其中,operator 是关键字,后面紧跟要重载的运算符,参数列表根据运算符的不同而有所变化。

运算符重载的类型

1. 成员函数重载

成员函数重载的运算符函数定义在类的内部,它隐含了一个 this 指针,指向调用该运算符的对象。

示例:

#include <iostream>class Complex {
private:double real;double imag;
public:Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}// 重载 + 运算符Complex operator+(const Complex& other) const {return Complex(real + other.real, imag + other.imag);}void display() const {std::cout << real << " + " << imag << "i" << std::endl;}
};int main() {Complex c1(1, 2);Complex c2(3, 4);Complex c3 = c1 + c2;c3.display();return 0;
}

在上述代码中,operator+ 是一个成员函数,它接受一个 const Complex& 类型的参数,返回一个新的 Complex 对象,表示两个复数相加的结果。

2. 非成员函数重载

非成员函数重载的运算符函数定义在类的外部,通常用于需要访问类的私有成员的情况,此时需要将该函数声明为类的友元函数。

示例:

#include <iostream>class Complex {
private:double real;double imag;
public:Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}// 声明友元函数friend Complex operator+(const Complex& c1, const Complex& c2);void display() const {std::cout << real << " + " << imag << "i" << std::endl;}
};// 非成员函数重载 + 运算符
Complex operator+(const Complex& c1, const Complex& c2) {return Complex(c1.real + c2.real, c1.imag + c2.imag);
}int main() {Complex c1(1, 2);Complex c2(3, 4);Complex c3 = c1 + c2;c3.display();return 0;
}

在这个例子中,operator+ 是一个非成员函数,它接受两个 const Complex& 类型的参数,返回一个新的 Complex 对象。通过将其声明为 Complex 类的友元函数,它可以访问 Complex 类的私有成员。

可重载和不可重载的运算符

  • 可重载的运算符:大多数运算符都可以重载,包括算术运算符(+-*/ 等)、关系运算符(==!=<> 等)、逻辑运算符(&&||!)、位运算符(&|^ 等)、赋值运算符(=+=-= 等)、自增自减运算符(++--)等。
  • 不可重载的运算符:一些运算符是不能重载的,如 .(成员访问运算符)、.*(成员指针访问运算符)、::(作用域解析运算符)、?:(条件运算符)和 sizeof 运算符。

注意事项

  • 不能改变运算符的优先级和结合性:运算符重载只是改变了运算符对自定义类型的操作行为,不能改变运算符原有的优先级和结合性。
  • 不能创建新的运算符:只能对已有的运算符进行重载,不能创造新的运算符。
  • 保持运算符的原有语义:在重载运算符时,应尽量保持运算符原有的语义,避免造成混淆。例如,重载 + 运算符应该实现加法的功能。

以下再举几个例子来解释说明运算符重载相关注意事项

重载操作符至少有一个类类型参数,不能改变内置类型对象含义。

“不能写 int operator+(int x, int y) 这种试图改变内置 int 类型加法含义的重载函数”  

1. C++ 的设计原则

C++ 语言设计时,为了保证语言的稳定性和可预测性,规定内置数据类型的运算符行为是固定的,不能被修改。例如,对于两个 int 类型的变量 a 和 ba + b 就是执行标准的整数加法运算,这是所有 C++ 程序员都默认和熟悉的行为。如果允许重载改变其含义,那么代码的可读性和一致性就会被破坏,可能会导致很多难以调试和理解的问题。

2. 示例说明

假设允许写 int operator+(int x, int y) 这样的函数来重载 int 类型的 + 运算符,比如:

int operator+(int x, int y) {return x * y;  // 这里试图让 + 运算符执行乘法的功能
}

然后在代码中使用:

int main() {int num1 = 3;int num2 = 4;int result = num1 + num2;  // 按照正常理解应该是 3 + 4 = 7,但因为重载改变了行为,实际执行的是 3 * 4 = 12return 0;
}

这样就会让原本熟悉 int 类型加法的程序员产生困惑,并且可能在各种依赖于标准加法运算的代码中引入错误,因为大家都默认 int 类型的 + 就是执行加法。

3. 正确的重载应用场景

运算符重载的正确使用场景是针对自定义类型。比如定义一个 Fraction 类表示分数:

class Fraction {
private:int numerator;  // 分子int denominator;  // 分母
public:Fraction(int num, int den) : numerator(num), denominator(den) {}// 重载 + 运算符,用于分数的加法Fraction operator+(const Fraction& other) {int newNumerator = numerator * other.denominator + other.numerator * denominator;int newDenominator = denominator * other.denominator;return Fraction(newNumerator, newDenominator);}
};

 在这个例子中,重载 + 运算符使得 Fraction 类型的对象可以像内置类型一样进行加法操作,而不会影响 int 等内置类型的 + 运算符的正常行为。

重载函数参数个数

一元运算符有一个参数,二元运算符有两个参数。成员函数形式的运算符重载,第一个运算对象由 this 指针隐式传递,参数比运算对象少

一个。

class Counter {
private:int count;
public:Counter(int c = 0) : count(c) {}// 成员函数形式重载 ++ 一元运算符Counter operator++() {count++;return *this;}
};

 上述代码中,Counter 类以成员函数重载前置 ++ 运算符,它只有一个隐含的 this 指针,无需额外参数。

以重载前置自增运算符 ++ 为例,假设有一个 Counter 类表示计数器:

class Counter {
private:int value;
public:Counter(int v = 0) : value(v) {}// 重载前置自增运算符,一元运算符,有一个参数(隐含的this指针指向调用对象)Counter operator++() {value++;return *this;}void display() {std::cout << "Value: " << value << std::endl;}
};

在上述代码中,operator++ 是重载的前置自增运算符函数。当使用 ++counter (counter 是 Counter 类的对象)这样的表达式时,operator++ 函数被调用,this 指针指向 counter 对象,函数对 value 进行自增操作。从参数角度看,这个函数虽然没有显式的参数,但通过 this 指针隐式地接收了一个运算对象,也就是调用该运算符的对象本身。

二元运算符

二元运算符作用于两个运算对象。在运算符重载函数中,就需要有两个参数来分别接收这两个运算对象。比如重载 + 运算符用于两个自定义类对象相加。

假设有一个 Complex 类表示复数:

class Complex {
private:double real;double imag;
public:Complex(double r = 0, double i = 0) : real(r), imag(i) {}// 非成员函数重载 + 运算符,二元运算符,有两个参数friend Complex operator+(const Complex& c1, const Complex& c2);
};Complex operator+(const Complex& c1, const Complex& c2) {return Complex(c1.real + c2.real, c1.imag + c2.imag);
}

这里的 operator+ 函数是重载的 + 运算符函数,它有两个参数 c1 和 c2 ,分别代表 + 运算符左右两边的 Complex 类对象。当执行 Complex c3 = c1 + c2; 这样的表达式时,c1 传递给第一个参数,c2 传递给第二个参数,函数执行复数相加的操作并返回结果。

成员函数形式的运算符重载

如果运算符重载函数是成员函数,那么第一个运算对象会默认通过 this 指针隐式传递,所以参数个数比运算对象的数量少一个。

还是以 Complex 类的 + 运算符重载为例,用成员函数形式来实现:

class Complex {
private:double real;double imag;
public:Complex(double r = 0, double i = 0) : real(r), imag(i) {}// 成员函数重载 + 运算符,二元运算符,但参数比运算对象少一个Complex operator+(const Complex& other) {return Complex(real + other.real, imag + other.imag);}
};

在这个成员函数形式的 operator+ 中,只有一个参数 other 。当执行 Complex c3 = c1 + c2; 时,c1 是调用该成员函数的对象,通过 this 指针隐式传递,c2 传递给 other 参数。函数内部通过 this 指针访问调用对象(c1 )的成员变量 real 和 imag ,并与 other (c2 )的成员变量进行相加运算。

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

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

相关文章

Salesforce 检索Layout的设定

做了许多Object&#xff0c;却想不起来怎么设置我的Listview的项目了。 問題&#xff1a; salesforce 最近参照したオブジェクト 表示項目を変更したいですが、「検索レイアウト」の選択メニューが該当オブジェクトのオブジェクトマネージャーから出てないです。 解決方法&am…

SECS/GEM300应用案例参考

GEM300 是一种用于半导体制造领域的通信协议标准&#xff0c;主要用于支持 300mm 晶圆制造的自动化生产。以下是 GEM300 的一些具体应用案例&#xff1a; 1. 半导体设备集成 设备制造商的应用&#xff1a;广州金南瓜科技有限公司通过 GEM300 SDK&#xff0c;帮助国内多个半导体…

win10系统上的虚拟机安装麒麟V10系统提示找不到操作系统

目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 win10系统上的虚拟机安装麒麟V10系统提示找不到操作系统&#xff0c;报错&#xff1a;Operating System not found 二、原因分析 国产系统&#xff0c;需要注意的点&#xff1a; 需要看你的系统类…

情书网源码 情书大全帝国cms7.5模板

源码介绍 帝国cms7.5仿《情书网》模板源码&#xff0c;同步生成带手机站带采集。适合改改做文学类的网站。 效果预览 源码获取 情书网源码 情书大全帝国cms7.5模板

C语言题目:链表数据求和操作

题目描述 读入10个复数&#xff0c;建立对应链表&#xff0c;然后求所有复数的和。 输入格式 无 输出格式 无 样例输入 1 2 1 3 4 5 2 3 3 1 2 1 4 2 2 2 3 3 1 1 样例输出 2323i 代码功能概述 createNode 函数&#xff1a; 创建一个包含 10 个复数节点的链表。 每个…

STM32 ADC介绍(硬件原理篇)

目录 背景 AD转换器 采样与保持 量化 编码 AD转换器转换原理 DA转换原理 AD转换原理 1.逐次逼近型AD转换器 2.并联比较型AD转换器 编码器 同步D触发器和边沿D触发器 基本RS触发器 同步RS触发器 同步D触发器 边沿型D触发器&#xff08;维持-阻塞D触发器&#xff…

公网远程家里局域网电脑过程详细记录,包含设置路由器。

由于从校内迁居小区,校内需要远程控制访问小区内个人电脑,于是早些时间刚好自己是电信宽带,可以申请公网ipv4不需要花钱,所以就打电话直接申请即可,申请成功后访问光猫设备管理界面192.168.1.1,输入用户名密码登录超管(密码是网上查下就有了)设置了光猫为桥接模式,然后…

流行编程语言全解析:优势、应用与短板

Python&#xff1a; 优势 Python 以其简洁、易读的语法闻名&#xff0c;新手能快速上手。丰富的库和框架&#xff0c;能极大地提高开发效率。 适用领域 数据科学与分析&#xff1a;处理和分析大规模数据集&#xff0c;进行数据可视化。典型示例&#xff1a;Google 用 Pytho…

统信服务器操作系统V20 1070A 安装docker新版本26.1.4

应用场景&#xff1a; 硬件/整机信息&#xff1a;x86平台、深信服超融合平台 OS版本信息&#xff1a;统信V20 1070a 1.获取docker二进制包 链接: https://pan.baidu.com/s/1SukBlra0mQxvslTfFakzGw?pwd5s5y 提取码: 5s5y tar xvf docker-26.1.4.tgz groupadd docker ch…

在 Vue 3 中使用 Lottie 动画:实现一个加载动画

在现代前端开发中&#xff0c;动画是提升用户体验的重要元素之一。Lottie 是一个流行的动画库&#xff0c;它允许我们使用 JSON 文件来渲染高质量的动画。本文将介绍如何在 Vue 3 项目中集成 Lottie 动画&#xff0c;并实现一个加载动画效果。 如果对你有帮助请帮忙点个&#x…

【Spring】Spring配置文件

目录 ​什么是配置文件&#xff1f; 配置文件的作用 SpringBoot配置文件 配置文件格式 配置文件的优先级 properties配置文件说明 properties基本语法 读取配置文件 properties缺点 yml配置文件说明 yml基本语法 使用yml连接数据库 yml配置不同数据类型及null 注意…

蓝桥杯篇---实时时钟 DS1302

文章目录 前言特点简介1.低功耗2.时钟/日历功能3.32字节的额外RAM4.串行接口 DS1302 引脚说明1.VCC12.VCC23.GND4.CE5.I/O6.SCLK DS1302 寄存器1.秒寄存器2.分钟寄存器3.小时寄存器4.日寄存器5.月寄存器6.星期寄存器7.年寄存器8.控制寄存器 DS1302 与 IAP25F2K61S2 的连接1.CE连…

Dubbo:高效的分布式服务框架

引言 在当今互联网应用的快速发展中&#xff0c;微服务架构已经成为一种主流的设计模式&#xff0c;它将一个大型单体应用拆分成多个小型、松耦合的服务。Dubbo 作为一款由阿里巴巴开源的 RPC 服务框架&#xff0c;专门为解决分布式系统中服务通信和治理的问题而设计。本文将深…

Visual Studio Code使用ai大模型编成

1、在Visual Studio Code搜索安装roo code 2、去https://openrouter.ai/settings/keys官网申请个免费的配置使用

【Javascript Day18】

目录 标签事件绑定的属性参数 阻止默认行为 dialog的实现及组织冒泡&#xff08;捕获&#xff09;传递 基于冒泡的事件委托 键盘事件的事件源对象信息 JS的自动触发操作 标签事件绑定的属性参数 <!-- 标签上的事件绑定&#xff0c;事件源对象通过 关键字event传递 --…

解锁机器学习核心算法 | 支持向量机:机器学习中的分类利刃

一、引言 在机器学习的庞大算法体系中&#xff0c;有十种算法被广泛认为是最具代表性和实用性的&#xff0c;它们犹如机器学习领域的 “十大神器”&#xff0c;各自发挥着独特的作用。这十大算法包括线性回归、逻辑回归、决策树、随机森林、K - 近邻算法、K - 平均算法、支持向…

玩客云 IP查找

1.玩客云使用静态IP在不同网段路由器下不能使用&#xff0c;动态不好找IP地址 1.1使用python3 实现自动获取发送 import requests import os import socket# 从环境变量获取 PushPlus 的 token 和群组编码 PUSH_PLUS_TOKEN os.getenv("PUSH_PLUS_TOKEN") PUSH_PLU…

Linux(Centos 7.6)命令详解:cat

1.命令作用 将文件或标准输入连接到标准输出(Concatenate FILE(s), or standard input, to standard output)&#xff0c; 即将文件内容输出到屏幕上&#xff0c;或者将多个文件合并成一个文件。 2.命令语法 Usage: cat [OPTION]... [FILE]... 3.参数详解 OPTION: -A, -…

深入解析Qt事件循环

在Qt开发中&#xff0c;QApplication::exec()这行代码是每个开发者都熟悉的“魔法咒语”。为什么GUI程序必须调用它才能响应操作&#xff1f;为何耗时操作会导致界面冻结&#xff1f;本文将以事件循环为核心&#xff0c;揭示Qt高效运转的底层逻辑&#xff0c;探讨其设计哲学与最…

Hive增量迁移方案与实操PB级

客户一共1PB数据&#xff0c;每天新增10T&#xff0c;有些表只保留3天。 需要客户提供&#xff1a; a.tbl_size(大小GB) a.last_mtime(最新更新时间) a.tbl_ttl(保留时间) b.last_part_dt(分区值) b.last_part_size(最新分区大小) t_day(表更新规律,t几) 因为目前…