Bootstrap

【C++学习】类和对象--运算符重载

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

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

目录

加号运算符重载

1.成员函数重载+

 2.全局函数重载+

        左移运算符重载<<

        递增运算符重载

        赋值运算符重载

        关系运算符重载

        函数调用运算符重载


加号运算符重载

1.成员函数重载+

#include<iostream>
#include<string>
using namespace std;
//加号运算符重载
class person
{
public:
	//1.成员函数重载+
	person operator + (person &p)//传入一个person类
	{
		person temp;
		temp.m_a = this->m_a + p.m_a;
		temp.m_b = this->m_b + p.m_b;
		return temp;
	}
	int m_a;
	int m_b;
};
void test01()
{
	person p1;
	p1.m_a = 10;
	p1.m_b = 10;
	person p2;
	p2.m_a = 10;
	p2.m_b = 10;
	person p3 = p1 + p2;
	cout << p3.m_a << " " << p3.m_b;
}

int main()
{
	test01();

	system("pause");
	return 0;
}

 2.全局函数重载+

#include<iostream>
#include<string>
using namespace std;
//加号运算符重载
class person
{
public:

	int m_a;
	int m_b;
};
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 = 10;
	p2.m_b = 10;
	person p3 = p1 + p2;
	cout << p3.m_a << " " << p3.m_b;
}

//2.全局函数重载+

int main()
{
	test01();

	system("pause");
	return 0;
}
	//成员函数重载本质调用
	person p3 = p1.operator +(p2);
	//全局函数重载本质调用
	person p3 = operator+(p1, p2);
    //简化版
    person p3=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;
}
person operator +(person& p1, int num)
{
	person temp;
	temp.m_a = p1.m_a + num;
	temp.m_b = p1.m_b + num;
	return temp;
}

总结1:对于内置的数据的表达式运算符是不可能改变的

                                        //最好只改变自定义类型表达式运算符

总结2:不要滥用运算符重载

左移运算符重载<<

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

#include<iostream>
#include<string>
using namespace std;
//左移运算符重载
class person
{
public:
	
	int m_a;
	int m_b;
};
//只能利用全局函数重载左移运算符
ostream& operator<<(ostream& nixx, person& p)
{//本质  operator<<(cout,p) ,简化   cout<<p
	nixx << p.m_a << " " << p.m_b ;
	return nixx;
}
void test01()
{
	person p;
	p.m_a = 10;
	p.m_b = 10;
	cout << p<<"    i want to play LOL"<<endl;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

递增运算符重载

作用:通过重载递增运算符,实现自己的整型数据

	//重载++运算符,++a
	myinteger& operator++()//如果返回 值,myint就只能进行一次递增
	{
		m_num++;
		return *this;//返回自身
	}
	myinteger operator++(int)//int代表一个占位参数,可以用于区分前置和后置递增
	{
		//先记录当时结果
		myinteger temp = *this;
		//后  递增
		m_num++;
		//最后将记录结果做返回
		return temp;
	}
#include<iostream>
#include<string>
using namespace std;
//重载递增运算符
// 
//自定义整型
class myinteger
{
	friend ostream& operator<<(ostream& cout, myinteger myint);
public:
	myinteger()
	{
		m_num = 0;
	}

	//重载++运算符,++a
	myinteger& operator++()//如果返回 值,myint就只能进行一次递增
	{
		m_num++;
		return *this;//返回自身
	}

	//重载++运算符,a++
	//后置递增一定要返回值
	myinteger operator++(int)//int代表一个占位参数,可以用于区分前置和后置递增
	{
		//先记录当时结果
		myinteger temp = *this;
		//后  递增
		m_num++;
		//最后将记录结果做返回
		return temp;
	}
private:
	int m_num;
};
ostream& operator<<(ostream& cout, myinteger myint)
{
	cout << myint.m_num;
	return cout;
}
void test01()
{
	myinteger myint;
	cout << ++myint << endl;
	cout << myint << endl;
}
void test02()
{
	myinteger myint;
	cout << myint++ << endl;;
	cout << myint << endl;
}
int main()
{
	//test01();
	test02();
	system("pause");
	return 0;
}

要注意,前置递增是返回引用,后置递增则返回值。

同时后置递增时,左移运算符重载时要把()里的第二个参数的&去掉。

并且,由于这一点,后置递增不适用于链式编程。


练习了一下递减运算符重载,理解了就很好敲。

#include<iostream>
#include<string>
using namespace std;
class myinteger
{
	friend ostream& operator << (ostream& cout, myinteger myint);
public:
	myinteger()
	{
		m_num = 8;
	}
	myinteger& operator--()
	{
		this->m_num--;
		return *this;//返回自身
	}
	myinteger operator--(int)
	{
		myinteger temp = *this;
		this->m_num--;
		return temp;//返回自身
	}
private:
	int m_num;
};
ostream& operator << (ostream & cout, myinteger  myint)
{
	cout << myint.m_num;
	return cout;
}
void test01()
{
	myinteger myint;
	cout << --myint << endl;
}
void test02()
{
	myinteger myint;
	cout << myint-- << endl;
	cout << myint << endl;
}
int main()
{
	//test01();
	test02();
	system("pause");
	return 0;
}

赋值运算符重载

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

        1.默认构造函数(无参,函数体为空

        2.默认析构函数(无参,函数体为空

        3.默认拷贝函数,对属性进行值拷贝

        4.赋值运算符 operator=,对属性进行值拷贝

如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题

#include<iostream>
#include<string>
using namespace std;
//赋值运算符重载
class person
{
public:
	person(int age)
	{
		m_age = new int(age);//把数据创建在堆区,并且用指针指向
	}
	//堆区数据需要我们手动开辟,手动释放
	//要提供析构函数,把数据释放干净
	~person()
	{
		if (m_age != NULL)
		{
			delete m_age;
			m_age = NULL;
		}
	}
	person& operator=(person&p)
	{
		//应该先判断是否有属性在堆区,要先释放干净,再进行深拷贝
		if (m_age != NULL)
		{
			delete m_age;
			m_age = NULL;
		}
		m_age = new int(*p.m_age);//深拷贝
		return *this;
	}
	int *m_age;//把年龄用指针,而其真实数据要开辟到堆区
};

void test01()
{
	person p1(18);
	person p2(20);
	person p3(30);

	p3 = p2 = p1;//赋值运算,简单的浅拷贝
	//指向同一块内存,导致后续内存重复释放,因此我们要利用深拷贝解决浅拷贝带来的问题
	cout << *p1.m_age<<endl;
	cout << *p2.m_age << endl;
	cout << *p3.m_age << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

关系运算符重载

这个比起上面简直是小巫见大巫~~

#include<iostream>
#include<string>
using namespace std;
//关系运算符重载
class person
{
public:

	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;
		}
		return false;
	}
	string m_name;
	int m_age;
};

void test01()
{
	person p1("胡图图",3);
	person p2("胡英俊", 3);
	if (p1 == p2)
	{
		cout << "same" << endl;
	}
	else cout << "different" << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

函数调用运算符重载

        函数调用运算符()也可以重载

        由于重载后使用的方式非常像函数的调用,因此称为仿函数

        仿函数没有固定写法,非常灵活

#include<iostream>
#include<string>
using namespace std;
//函数调用运算符重载
class myprint
{
public:
	//重载函数调用运算符
	void operator()(string test)
	{
		cout << test << endl;
	}
	
};
class myadd
{
public:
	int operator()(int num1, int num2)
	{
		return num1 + num2;
	}

};
void test01()
{
	myprint print;
	print("hello hututu");

	myadd add;
	cout<<add(78, 98)<<endl;

	//匿名函数对象
	cout << myadd()(100, 100) << endl;//即不先创建一个myadd类,匿名对象执行完立即释放
	//通过一个类型和()会创建一个匿名对象
}

int main()
{
	test01();
	system("pause");
	return 0;
}
;