C++ 运算符重载 (备查)

发布时间:2023年12月17日

基础

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

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

语法:

void operator@();	//@代表了被重载的运算符。

函数的参数个数取决于两个因素。
	1)运算符是一元(一个参数)的还是二元(两个参数)2)运算符被定义为全局函数(对于一元是一个参数,对于二元是两个参数)
	还是成员函数(对于一元没有参数,对于二元是一个参数-此时该类的对象用作左耳参数)

成员函数重载 + 全局函数重载 原理

在这里插入图片描述

运算符重载(operator overloading)只是一种”语法上的方便”,也就是它只是另一种函数调用的方式。

是否可重载

在这里插入图片描述

几乎C中所有的运算符都可以重载,但运算符重载的使用时相当受限制的。

不能改变运算符优先级,不能改变运算符的参数个数。

加号(+)运算符重载

//利用成员函数实现加号运算符重载
Person operator+(Person &p)
{
	Person temp;
	temp.m_A = this->m_A + p.m_A;
	temp.m_B = this->m_B + p.m_B;
	return temp;
}

private:
	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;
}

重载左移操作符(<<),使得 cout 可以输出自定义对象

为什么不用 成员函数重载 实现

在这里插入图片描述

使用 全局函数 重载 << 运算符(无法链式编程)

在这里插入图片描述

cout 是 ostream 类的对象,全局只有一个,所以使用 & 。

要实现 cout 链式输出需返回 cout 引用

在这里插入图片描述

如果要访问类中私有属性,配合友元实现
//重载 << 运算符案列
class Person{
	friend ostream& operator<<(ostream& os, Person& person);//友元
public:
	Person(int id,int age){
		mID = id;
		mAge = age;
	}
private:
	int mID;
	int mAge;
};

//重载 <<  运算符
ostream& operator<<(ostream& os, Person& person){
	os << "ID:" << person.mID << " Age:" << person.mAge;
	return os;
}

int main(){

	Person person(1001, 30);
	//cout << person; //cout.operator+(person)
	cout << person << " | " << endl;

	return EXIT_SUCCESS;
}

自增自减(++/–)运算符重载

class Complex{

public:
	Complex(){
		mA = 0;
		mB = 0;
	}
	//重载前置++
	Complex& operator++(){
		mA++;
		mB++;
		return *this;	//返回的的是引用,可以实现链式编程:(++(++b))
	}
	//重载后置++
	Complex operator++(int){	
		Complex temp;
		temp.mA = this->mA;
		temp.mB = this->mB;
		mA++;
		mB++;
		return temp;	//temp是局部对象,不能返回引用,所以不能实现链式编程。
	}
	//前置--
	Complex& operator--(){
		mA--;
		mB--;
		return *this;
	}
	//后置--
	Complex operator--(int){
		Complex temp;
		temp.mA = mA;
		temp.mB = mB;
		mA--;
		mB--;
		return temp;
	}

private:
	int mA;
	int mB;
};

如何区分重载的前置++还是后置++,通过占位参数来区分,有 int 的为后置++,- - 同理。

要优先使用前缀形式,由于前缀形式创建了一个临时对象,效率经常会略高一些。

指针运算符( *、-> )重载

利用智能指针,管理 new 出来的 Person 的释放操作。

//被维护的类
class Person{
public:
	Person(int param){
		this->mParam = param;
	}
	void PrintPerson(){
		cout << "Param:" << mParam << endl;
	}
private:
	int mParam;
};

//智能指针
class SmartPointer{
public:
	SmartPointer(Person* person){
		this->pPerson = person;
	}
	
	//重载指针的 -> 操作符
	Person* operator->(){
		return pPerson;
	}
	//重载指针的 * 操作符
	Person& operator*(){
		return *pPerson;
	}
	
	~SmartPointer(){
		if (pPerson != NULL){
			delete pPerson;	//在析构中释放 被维护对象空间
			this.pPerson = NULL;
		}
	}
public:
	Person* pPerson;	//维护一个被管理类的指针
};

void test01(){
	SmartPointer pointer(new Person(18));	//通过构造,实例化被被维护的对象
	
	//本质:pointer->->PrintPerson(); 编译器简化为:pointer->PrintPerson();
	pointer->PrintPerson();	
	(*pointer).PrintPerson();
}

智能指针类 执行在栈上,执行完后自动释放,同时也释放了被维护对象的空间。

自动释放体现出:智能
指针运算符( * ,-> )重载体现出: 指针

赋值(=)运算符重载

编译器 默认给一个类提供四个函数:默认构造,拷贝构造(浅拷贝),析构函数 ,operator= (浅拷贝)。

在这里插入图片描述

//赋值(=)运算符重载-------详细案列
class Person{
	friend ostream& operator<<(ostream& os,const Person& person){
		os << "ID:" << person.mID << " Age:" << person.mAge << endl;
		return os;
	}
public:
	Person(int id,int age){
		this->mID = id;
		this->mAge = age;
	}
	//重载赋值运算符
	Person& operator=(const Person& person){
		this->mID = person.mID;
		this->mAge = person.mAge;
		return *this;
	}
private:
	int mID;
	int mAge;
};

//1. =号混淆的地方
void test01(){
	Person person1(10, 20);
	Person person2 = person1; //调用拷贝构造
	//如果一个对象还没有被创建,则必须初始化,也就是调用构造函数
	//上述例子由于person2还没有初始化,所以会调用构造函数
	//由于person2是从已有的person1来创建的,所以只有一个选择
	//就是调用拷贝构造函数
	person2 = person1; //调用operator=函数
	//由于person2已经创建,不需要再调用构造函数,这时候调用的是重载的赋值运算符
}
//2. 赋值重载案例
void test02(){
	Person person1(20, 20);
	Person person2(30, 30);
	cout << "person1:" << person1;
	cout << "person2:" << person2;
	person2 = person1;
	cout << "person2:" << person2;
}
//常见错误,当准备给两个相同对象赋值时,应该首先检查一下这个对象是否对自身赋值了
//对于本例来讲,无论如何执行这些赋值运算都是无害的,但如果对类的实现进行修改,那么将会出现差异;
//3. 类中指针
class Person2{
	friend ostream& operator<<(ostream& os, const Person2& person){
		os << "Name:" << person.pName << " ID:" << person.mID << " Age:" << person.mAge << endl;
		return os;
	}
public:
	Person2(char* name,int id, int age){
		this->pName = new char[strlen(name) + 1];
		strcpy(this->pName, name);
		this->mID = id;
		this->mAge = age;
	}
#if 1
	//重载赋值运算符
	Person2& operator=(const Person2& person){

		//注意:由于当前对象已经创建完毕,那么就有可能pName指向堆内存
		//这个时候如果直接赋值,会导致内存没有及时释放
		if (this->pName != NULL){
			delete[] this->pName;
		}

		this->pName = new char[strlen(person.pName) + 1];
		strcpy(this->pName,person.pName);
		this->mID = person.mID;
		this->mAge = person.mAge;
		return *this;
	}
#endif
	//析构函数
	~Person2(){
		if (this->pName != NULL){
			delete[] this->pName;
		}
	}
private:
	char* pName;
	int mID;
	int mAge;
};

void test03(){
	Person2 person1("John",20, 20);
	Person2 person2("Edward",30, 30);
	cout << "person1:" << person1;
	cout << "person2:" << person2;
	person2 = person1;
	cout << "person2:" << person2;
}

等于和不等于(==、!=)运算符重载

class Complex{
public:
	Complex(char* name,int id,int age){
		this->pName = new char[strlen(name) + 1];
		strcpy(this->pName, name);
		this->mID = id;
		this->mAge = age;
	}
	//重载==号操作符
	bool operator==(const Complex& complex){
		if (strcmp(this->pName,complex.pName) == 0 && 
		    this->mID == complex.mID && 
			this->mAge == complex.mAge){
			return true;
		}
		return false;
	}
	//重载!=操作符
	bool operator!=(const Complex& complex){
		if (strcmp(this->pName, complex.pName) != 0 || 
		    this->mID != complex.mID || 
			this->mAge != complex.mAge){
			return true;
		}
		return false;
	}
	~Complex(){
		if (this->pName != NULL){
			delete[] this->pName;
		}
	}
private:
	char* pName;
	int mID;
	int mAge;
};
void test(){
	Complex complex1("aaa", 10, 20);
	Complex complex2("bbb", 10, 20);
	if (complex1 == complex2){ cout << "相等!" << endl; }
	if (complex1 != complex2){ cout << "不相等!" << endl; }
}

函数调用符号()重载——(仿函数)

class Complex{
public:
	int Add(int x,int y){
		return x + y;
	}
	int operator()(int x,int y){
		return x + y;
	}
};
void test01(){
	Complex complex;
	cout << complex.Add(10,20) << endl;
	//对象当做函数来调用
	cout << complex(10, 20) << endl;
	//使用匿名对象 用完立即释放
	cout << complex()(10, 20) << endl;
}

不要重载&&、||

不能重载 operator&& 和 operator|| 的原因是,无法在这两种情况下实现内置操作符的完整语义。(即:不能实现短路特性

符号重载建议

在这里插入图片描述

=, [], () 和 -> 操作符只能通过成员函数进行重载

<< 和 >>只能通过全局函数配合友元函数进行重载

不要重载 && 和 || 操作符,因为无法实现短路规则

文章来源:https://blog.csdn.net/CYS_2020/article/details/134992075
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。