什么是运算符重载? 如何在 C++ 中进行运算符重载?运算符重载在面向对象编程中的好处是什么?

发布于:2024-12-18 ⋅ 阅读:(78) ⋅ 点赞:(0)

什么是运算符重载

运算符重载是一种允许用户重新定义 C++ 中大多数运算符的功能的机制。在 C++ 中,运算符(如+、-、*、/等)本来有其预定义的操作,比如对于基本数据类型(int、float等)的加法操作。但是,当我们处理自定义的数据类型(如类和结构体)时,通过运算符重载,可以赋予这些运算符新的含义,使其能够像操作基本数据类型一样方便地操作自定义类型。

例如,我们有一个复数类Complex,它包含实部和虚部两个成员变量。如果没有运算符重载,对两个复数进行相加操作就会很麻烦,可能需要定义一个专门的函数来实现加法。但是通过重载+运算符,就可以像Complex c3 = c1 + c2;这样直观地进行复数相加操作,其中c1、c2和c3是Complex类的对象。

如何在 C++ 中进行运算符重载

成员函数方式

加号运算符重载

作用:实现两个自定义数据类型相加的运算

#include<iostream>
using namespace std;

class Box
{
	int height;
	int width;
	int length;
public:
	Box() :height(0), width(0), length(0) {}
	Box(int l, int w, int h) :height(h), width(w), length(l) {}
	Box(const Box &other)
	{
		this->height = other.height;
		this->width = other.width;
		this->length = other.length;
	}

	Box operator+ (const Box & other)//加&避免调用拷贝构造
    //返回值不加引用,是因为返回的是局部变量,函数结束会被释放
	{
		Box c;
		c.length = other.length + this->length;
		c.width = other.width + this->width;
		c.height = other.height + this->height;
		return c;
	}

	void Print()
	{
		cout << width << "  " << length << "  " << height << endl;
	}
	~Box()
	{
		cout << "析构函数" << endl;
	}
};

int main()
{
	Box a(1,1,1), b(1,1,1);
	Box c = a + b;
	c.Print();
	
}

左移运算符重载

作用:可以输出自定义数据类型

#include<iostream>
#include<string>
using namespace std;

class Box
{
	int height;
	int width;
	int length;
public:
	friend ostream&  operator<<(ostream &o, Box a);
	Box() :height(0), width(0), length(0) {}
	Box(int l, int w, int h) :height(h), width(w), length(l) {}
	Box(const Box &other)
	{
		this->height = other.height;
		this->width = other.width;
		this->length = other.length;
	}
	void Print()
	{
		cout << width << "  " << length << "  " << height << endl;
	}
	~Box()
	{
		cout << "析构函数" << endl;
	}
};
//左移运算符要在类外实现
ostream&  operator<<(ostream &o ,Box a)
{
	o << a.height << "  " << a.length << "  " << a.width << endl;
	return o;
}

int main()
{
	Box a(1, 1, 1),b;
	cout << a << b;
}

+=递增运算符重载

#include<iostream> 
using namespace std;

class Box
{
	int length;
	int width;
	int height;
public:
	friend ostream& operator<<(ostream& o, Box b);
	Box() :length(0), width(0), height(0) {}
	Box(int l, int w, int h) :length(l), width(w), height(h) {}
	Box(const Box& other)
	{
		this->length = other.length;
		this->height = other.height;
		this->width  =  other.width;
	}
	Box& operator+=(const Box& other) //可以引用返回*this,因为*this这个对象没在当前函数内创建,在主函数创建的,主函数如果是a+=b,那么*this是a
	{
		this->height += other.height;
		this->length += other.length;
		this->width += other.width;
		return *this;
	}
};
ostream& operator<<(ostream& o,Box b)
{
	o << b.length << "  " << b.width << "  " << b.height << endl;
	return o;
}

int  main()
{
	Box a(1,1,1), b(2,2,2),c(3,3,3);
	a += b += c;
	cout <<a << b << c << endl;
}

递增运算符重载

class Integer
{
	int num;
public:
	Integer() :num(0) {}
	Integer(int val) :num(val) {}
	Integer operator++ ()
	{
		this->num += 1;
		return *this;
	}
	Integer operator++ (int) //使用参数占位符来区分前++和后++,有参数占位符的为后++
	{
		Integer other = *this;
		this->num += 1;
		return other;
	}
};

关系运算符

#include<iostream>
using namespace std;
#include<string>
#include<vector>

class A
{
	int num;
public:
	A() :num(0) {}
	A(int num) :num(num) {}

	bool operator> (const A& other)
	{
		if (this->num > other.num) return 1;
		return 0;
	}

	bool operator ==(const A& other)
	{

		if (this->num == other.num) return 1;
		return 0;
	}
};

int main() {

	A a(2), b;
	cout << (a > b);
	return 0;
}

赋值运算符

#include<iostream>
using namespace std;
#include<string>
#include<vector>

class A
{
	int num;
	int *p;
public:
	A() :num(0),p(nullptr) {}
	A(int num) :num(num),p(new int(num)) {}
	~A()
	{
		if (p) delete p;
	}
	A& operator= (const A&other)
	{
		if (p) delete p; //释放原来指向的堆区内存,拷贝构造没有这一步骤
		num = other.num;
		p = new int(num); //指向新的堆区内存
		return *this;
	} 
};

int &fun()
{
	int a = 2;
	return a;
}

int main() {

	int b = fun(); //行
	int &c = fun(); //不行

	A a(2), b(3),c;
	a = b = c; // 如果类内没有实现赋值运算符,编译器则会提供默认的赋值运算符,每个成员都会被赋值,此时要注意浅拷贝问题
	return 0;
}

非成员函数方式(友元函数)

有时候,我们可能需要访问类的私有成员来进行运算符重载,这时可以使用友元函数。例如,对于上面的Vector2D类,如果我们想通过非成员函数来重载+运算符:

class Vector2D {
     public:
         double x;
         double y;
         Vector2D(double a = 0, double b = 0) : x(a), y(b) {}
         friend Vector2D operator+(const Vector2D& v1, const Vector2D& v2);
     };
     Vector2D operator+(const Vector2D& v1, const Vector2D& v2) {
         return Vector2D(v1.x + v2.x, v1.y + v2.y);
     }

运算符重载在面向对象编程中的好处

提高代码的可读性和可维护性

当处理自定义类型时,按照人们习惯的运算符方式来操作对象,会使代码更加直观。例如,对于矩阵类Matrix,如果要实现两个矩阵相加,重载+运算符后,代码Matrix c = a + b;比调用一个名为addMatrices之类的函数(如Matrix c = addMatrices(a, b);)更容易理解。这种直观的表达方式符合人们对数学运算的习惯,使得代码的意图更加清晰,降低了理解代码的难度,从而提高了代码的可维护性。

代码的复用性增强

一旦正确地重载了运算符,这些运算符可以在整个程序中以相同的方式用于自定义类型的对象,就像它们用于基本数据类型一样。例如,我们重载了+和*运算符用于复数类Complex,那么在任何需要对复数进行加法和乘法的地方,都可以直接使用这些运算符,而不需要重新编写专门的函数来实现相同的操作。这减少了代码的冗余,提高了代码的复用性。

更好地体现面向对象编程的封装性和抽象性

通过运算符重载,可以将对自定义类型对象的复杂操作封装在运算符函数内部。例如,对于一个日期类Date,重载+运算符来实现日期的加法(如加上一定天数),用户在使用Date类对象时,不需要了解日期加法的具体实现细节,只需要使用+运算符即可。这使得类的接口更加简洁和抽象,隐藏了内部的实现细节,符合面向对象编程的封装和抽象原则。


网站公告

今日签到

点亮在社区的每一天
去签到