C++运算符重载

文章目录

  • C++运算符重载
    • 1. 加号运算符(+)重载
      • 代码实现
    • 2.左移运算符(cout)重载
      • 代码实现
    • 3.递增运算符(++)重载
      • 代码实现
    • 4.赋值运算符(=)重载
      • 代码实现
    • 5.关系运算符(==)重载
      • 代码实现
    • 6.函数调用运算符()重载
      • 代码实现

C++运算符重载

​ 运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

​ 运算符重载,也可以发生函数重载

1. 加号运算符(+)重载

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

代码实现

#include 
using namespace std;

class Person {
public:
	//1.成员函数重载+号,本质调用为Person p3 = p1.operator+(p2);
	Person operator+(Person& p)
	{
		Person temp;
		temp.m_A = this->m_A + p.m_A;
		temp.m_B = this->m_A + p.m_B;
		return temp;
	}

	int m_A;
	int m_B;
};

//2.全局函数重载+号,本质调用为Person p3 = operator+(p1,p2);
//Person operator+(Person &p1, Person &p2)
//{
//	Person temp;
//	temp.m_A = p1.m_A + p2.m_A;
//	temp.m_B = p1.m_B + p2.m_B;
//	return temp;
//}

void test01()
{
	Person p1;
	p1.m_A = 10;
	p1.m_B = 10;
	Person p2;
	p2.m_A = 20;
	p2.m_B = 20;

	Person p3 = p1 + p2;
	cout << "p3.m_A= " << p3.m_A << endl;
	cout << "p3.m_B= " << p3.m_B << endl;
}

int main()
{
	test01();
	return 0;
}

2.左移运算符(cout)重载

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

代码实现

#include 
using namespace std;

class Person {
public:
	//通常,我们不会利用成员函数重载左移运算符,因为无法将cout在左侧实现,调用时得写成p<

3.递增运算符(++)重载

作用:通过重载递增运算符,实现自己的整形数据递增。不过同样的道理,也可以写出递减运算符重载

代码实现

#include 
using namespace std;

class MyInteger
{
public:
	MyInteger()
	{
		m_Num = 10;
	}

	//重载前置++运算符(++i)
	MyInteger &operator++()
	{
		++m_Num;
		return *this;		//将类本身做返回
	}

	//重载后置++运算符(i++)
    //因为函数返回的是局部变量temp,当函数调用完后会释放局部变量,所以函数只能返回值,而不是引用&
	MyInteger operator++(int)	//int 代表占位参数,用于区分前置和后置递增
	{
		MyInteger temp = *this;
		m_Num++;
		return temp;		//将类本身做返回
	}

	int m_Num;
};

ostream &operator<<(ostream &cout, MyInteger &myint)
{
	cout << myint.m_Num;
	return cout;
}

int main()
{
	MyInteger myint;
	cout << ++myint << endl;
	return 0;
}

递增运算符分前置递增(++i)和后置递增(i++),两者写法分别为:

  • 重载前置递增运算符:

    函数返回值 &operator++();

  • 重载后置递增运算符:

    函数返回值 operator++(int);

注意:

(1).重载前置运算符不需要传入参数,而重载后置运算符需要传入一个占位参数int;

(2).重载前置运算符返回的是引用,后续可以对该值继续链式调用; 重载后置运算符直接返回局部变量的,因为局部变量在函数调用完后就被释放,所以如果引用一个局部变量地址就会报错。

4.赋值运算符(=)重载

C++编译器至少给一个类添加了4个默认函数:

  1. 默认构造函数(无参)
  2. 默认析构函数(无参)
  3. 默认拷贝构造函数,对属性进行浅拷贝
  4. 赋值运算符operator=,对属性进行值拷贝

只要涉及到值的拷贝问题,就必须要搞清楚是深拷贝(拷贝对象和原对象指向不同存储空间)还是浅拷贝(拷贝对象和原对象指向同一片存储空间,可能引发释放问题)

代码实现

#include 
using namespace std;

class Person {
public:
	int *m_Age;

	Person(int age)	
	{
		m_Age = new int(age);
	}

	~Person()		//写出析构函数是为了方便看出浅拷贝和深拷贝的区别
	{
		if (m_Age) {
			delete m_Age;
			m_Age = NULL;
		}
	}

	Person &operator=(Person& p)
	{
		//先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
		if (m_Age)
		{
			delete m_Age;
			m_Age = NULL;
		}
		//深拷贝
		m_Age = new int(* p.m_Age);
		
		//编译器只提供如下浅拷贝:
		//m_Age = p.m_Age;

		return *this;
	}
};

void test()
{
	Person p1(10);
	Person p2(20);

	p2 = p1;		//赋值操作,调用重载函数

	cout << "p1.m_Age= " << *p1.m_Age << endl;
	cout << "p2.m_Age= " << *p2.m_Age << endl;
}

int main()
{
	test();
	return 0;
}

5.关系运算符(==)重载

在做对比操作时,如果需要对比的是两个类中的成员值,这就需要我们自己重载等值运算符,选取需要对比的成员。

代码实现

#include 
using namespace std;

class Person {
public:
	string m_Name;
	int m_Age;

	Person(string name, int age)		//有参构造函数
	{
		m_Name = name;
		m_Age = age;
	}

	bool operator==(Person& p)		//等值运算符重载
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {
			return true;
		}
		else {
			return false;
		}
	}

};

int main()
{
	Person p1("张三",10);
	Person p2("李四", 20);
	if (p1 == p2) {
		cout << "p1 和 p2相等" << endl;
	}
	else {
		cout << "p1 和 p2不相等" << endl;
	}
	return 0;
}

同样的道理,也可以重载!=运算符、小于<运算符、大于>运算符等。

6.函数调用运算符()重载

​ 没错,这里重载的就是一对小括号()

  • 由于重载后使用的方式比较像函数的调用,使用也称之为仿函数。仿函数没有固定写法,非常灵活

代码实现

#include 
using namespace std;

class MyPrint
{
public:
	void operator()(string str)
	{
		cout << str << endl;
	}
};

int main()
{
	MyPrint myprint;

	myprint("hello world!");		//这里的()使用了重载函数,其本身也像一个函数

	return 0;
}

上面代码中是将()重载为了输出函数,作为仿函数,它可以实现各种功能,前面几种重载类型几乎都可以用调用运算符重载实现(没去试验,我猜的),注意后期使用不要混淆。

你可能感兴趣的:(c++,开发语言)