运算符重载(一)

server/2024/12/26 0:50:10/

知识图谱

一.需要重载的原因

正常情况下,C++ 的运算符( +、-、*、/ 等)只能用于对基本类型的常量或变量进行运算,而不能用于类对象之间的运算。

类的对象直接的运算虽然可以通过成员函数或全局函数去实现,如date.Add(1),但这样的写法有时不易理解。

C++的提供了重载运算符的特性,允许将一些常见的运算符根据自定义类型的需要去重新定义,尽量让对象之间的运算可以像基本类型的运算一样简单、好理解。

二.声明、定义重载运算符函数 

1.定义

返回值类型 operator 运算符(形参列表)
{...
}

返回值一般是一个类

  • 一元运算符重载:一元运算符只有一个操作数。在重载一元运算符时,通常将其定义为类的成员函数,没有参数(除了隐式的this指针)。
  • 二元运算符重载:二元运算符有两个操作数。在重载二元运算符时,可以选择将其定义为类的成员函数或非成员函数。
  • 如果将二元运算符定义为类的成员函数,参数列表将包括一个额外的参数,表示右侧操作数。左侧操作数则是隐式的this指针。
  • 如果将二元运算符定义为非成员函数(全局函数或友元函数),参数列表将包括两个参数,分别表示左侧和右侧操作数

 2.重载运算符的例子

(1)单目运算符
#include <iostream>
using namespace std;class A
{
private:int x, y;
public:A(int x1 = 0, int y1 = 0){x = x1;y = y1;}A &operator++()//++i 前置++实现{++x;	//先自增++y;return *this;	//后引用}A operator++(int)	//i++ 后置++实现{//int参数没有任何意义,只是为了区分是前置还是后置形式A a = *this;	//保存对象引用++(*this);	//自增,调用前面实现的前置++return a;	//返回先前保存的对象}void show(){cout << "x=" << x << "," << "y=" << y << endl;}
};
int main()
{A a1(1, 2), a2(3, 4);(a1++).show();(++a2).show();return 0;
}

输出:

x=1,y=2x=4,y=5

前置运算符:++a,先++,后赋值(返回引用)

后置运算符:--a,先赋值(赋值的方法,定义一个类来保存先前对象的引用),然后调用前面的前置++运算符实现自增,最后返回先前保存的对象。注意:后置的++要带上参数int用来区别前置运算符

#include <iostream>class MyClass {
private:int value;
public:MyClass() : value(0) {}  // 构造函数MyClass(int val) : value(val) {}  // 带参数的构造函数// 后置自增运算符的重载MyClass operator++(int) {MyClass temp = *this;  // 保存当前对象的一个副本value++;               // 自增成员变量return temp;           // 返回副本(未自增的状态)}int getValue() const {return value;}
};int main() {MyClass obj(10);std::cout << "Before increment: " << obj.getValue() << std::endl;MyClass obj2 = obj++;  // 使用后置自增std::cout << "After increment: " << obj.getValue() << std::endl;std::cout << "Copy before increment: " << obj2.getValue() << std::endl;return 0;
}

若没有前置++的版本,后置的++需要自增成员变量

(2)双目运算符
加法重载运算符

成员函数

#include <iostream>
using namespace std;class A
{
private:int x, y;
public:A(int x1 = 0, int y1 = 0){x = x1;y = y1;}A operator+(const A& a)const{A t;t.x = this->x + a.x;t.y = this->y + a.y;return t;}void show(){cout << "x=" << x << "," << "y=" << y << endl;}
};
int main()
{A a1(1, 2);A a2(3, 4);A a;a = a1 + a2;a.show();
}

左值无需用参数,直接就用this传

全局函数

#include <iostream>
using namespace std;class A
{
private:int x, y;
public:A(int x1 = 0, int y1 = 0){x = x1;y = y1;}friend A operator+(const A& a, const A& b);void show(){cout << "x=" << x << "," << "y=" << y << endl;}
};
A operator+(const A& a, const A& b)
{return A(a.x + b.x, a.y + b.y);
}
int main()
{A a1(1, 2), a2(3, 4);A c;c = a1 + a2;c.show();return 0;
}

注意其书写形式

`const A& a`是一种参数传递的方式,表示`a`是一个对类型`A`的常量引用。

(3) 关系运算符重载
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//private:int _year;int _month;int _day;
};//operator运算符 做函数名
bool operator == (const Date& x, const Date& y)
{return x._year == y._year&& x._month == y._month&& x._day == y._day;
}bool operator < (const Date& x, const Date& y)
{if (x._year < y._year){return true;}else if (x._year == y._year){if (x._month < y._month){return true;}else if (x._month == y._month){return x._day < y._day;}}return false;
}
int main()
{Date d1(2024, 1, 28);Date d2(2024, 1, 29);cout << operator == (d1, d2) << endl;cout << operator < (d1, d2) << endl;cout << (d1 == d2) << endl;cout << (d1 < d2) << endl;return 0;
}

注意其书写形式

 赋值运算符
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << '/' << _month << '/' << _day << endl;}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;
};int main()
{Date d1(2024, 2, 01);Date d2(2024, 2, 02);Date d3(2024, 2, 03);d1 = d2 = d3;d1.Print();d2.Print();d3.Print();return 0;
}

在赋值运算符重载函数中,通常需要执行以下操作:

  1. 检查是否是自我赋值,即当前对象和要赋值的对象是否是同一个对象。如果是同一个对象,则直接返回当前对象,避免不必要的操作。

  2. 进行属性的深拷贝,将要赋值的对象的属性逐个复制给当前对象的属性。

  3. 返回当前对象的引用。

为何使用引用

  • 引用参数:赋值运算符需要修改当前对象的值,而不是创建一个新的对象。因此,使用引用参数,可以直接修改当前对象而不是在函数内部创建一个副本
  • 返回this指针:赋值运算符一般返回当前对象的引用,即*this。这样可以实现连续赋值操作,例如 a = b = c。通过返回this指针,可以链式调用赋值运算符
(4)流输入与流输出运算符重载(以复数为例)
流输出
#include <iostream>using namespace std;class Complex {
private:double real;double imag;public:Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}friend ostream& operator<<(ostream& out, const Complex& c);
};ostream& operator<<(ostream& out, const Complex& c) {out << "(" << c.real << ", " << c.imag << ")";return out;
}int main() {Complex c1(3.0, 4.5);cout << "The complex number is: " << c1 << endl;return 0;
}
  • operator<< 被定义为一个友元函数。
  • 函数参数包括输出流对象(通常是ostream&)和常量引用的复数对象
  • 函数返回输出流对象的引用以便支持链式调用(如cout << c1 << c2)。
  • 注意:里面的<<是ostream的成员函数
流输入
#include <iostream>using namespace std;
class Complex {
private:double real;double imag;public:Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}friend istream& operator>>(istream& in, Complex& c);
};istream& operator>>(istream& in, Complex& c) {in >> c.real >> c.imag;return in;
}int main() {Complex c2;cout << "Enter a complex number (real and imaginary parts): ";cin >> c2;cout << "You entered: " << c2 << endl;return 0;
}
  • operator>> 被定义为一个友元函数。
  • 函数参数包括输入流对象(通常是std::istream&)和非常量引用的复数对象。
  • 函数返回输入流对象的引用以便支持链式调用(如std::cin >> c1 >> c2)。

http://www.ppmy.cn/server/153184.html

相关文章

xshell下载和安装(超详细)

参考:https://blog.csdn.net/hffh123/article/details/135885175 一、xshell官网下载 下载官网&#xff1a;https://www.xshell.com/zh/free-for-home-school/ 二、安装步骤 &#xff08;一&#xff09;、直接打开.exe文件 &#xff08;二&#xff09;、点击下一步&#xff…

高并发处理 --- Caffeine内存缓存库

目录 一.什么是Caffeine&#xff1f; 使用场景&#xff1a; 二.如何使用Caffeine&#xff1f; 1.导入依赖&#xff1a; 2.在java项目中使用&#xff1a; 三.对缓存项的驱逐&#xff1a; 1.容量驱逐&#xff08;Maximum Size&#xff09;&#xff1a; 2.过期驱逐&#xff…

【开源库 | xlsxio】C/C++读写.xlsx文件,xlsxio 在 Linux(Ubuntu18.04)的编译、交叉编译

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-12-20 …

CASA模型相关遥感数据及MODIS NDVI、FPAR遥感产品数据时序重建

植被作为陆地生态系统的重要组成部分对于生态环境功能的维持具有关键作用。植被净初级生产力&#xff08;Net Primary Productivity, NPP&#xff09;是指单位面积上绿色植被在单位时间内由光合作用生产的有机质总量扣除自养呼吸的剩余部分。植被NPP是表征陆地生态系统功能及可…

Bazel CI

本文来自智谱清言 ------ “Bazel CI” 通常指的是使用 Bazel 构建工具的持续集成&#xff08;CI&#xff09;系统。Bazel 是一个由 Google 开发的开源构建和测试工具&#xff0c;它支持多种编程语言&#xff0c;并被设计用于构建大型代码库。在持续集成环境中&#xff0c;B…

Java的垃圾回收机制介绍、工作原理、算法及分析调优

Java的垃圾回收&#xff08;Garbage Collection&#xff0c;GC&#xff09;是Java虚拟机&#xff08;JVM&#xff09;提供的一种自动内存管理机制&#xff0c;用于自动回收不再使用的内存空间&#xff0c;以避免内存泄露和内存溢出等问题。下面主要介绍Java垃圾回收的基本概念、…

[flutter] 容器组件

Center Center容器用来居中widget const Center({Key key, double widthFactor, // 若该值为空&#xff0c;该组件宽度会尽可能大&#xff1b;若不为空&#xff0c;该组件的宽度就是子节点宽度的多少倍double heightFactor, // 同widthFactorWidget child // 子组件 }) : supe…

苍穹外卖-day05redis 缓存的学习

苍穹外卖-day05 课程内容 Redis入门Redis数据类型Redis常用命令在Java中操作Redis店铺营业状态设置 学习目标 了解Redis的作用和安装过程 掌握Redis常用的数据类型 掌握Redis常用命令的使用 能够使用Spring Data Redis相关API操作Redis 能够开发店铺营业状态功能代码 功能实…