一文带你搞懂C++运算符重载

152 阅读6分钟

7. C++运算符重载

C++运算符重载

什么是运算符重载

  • 运算符重载赋予运算能够操作自定义类型。

  • 运算符重载前提条件: 必定存在一个自定义类型

  • 运算符重载实质: 就是函数调用

    • 友元重载

    • 类重载

  • 在同一自定义类型中,一个运算符只能被重载一次

  • C++重载只能重载已有的运算符,不能重载没有

  • C++重载一般情况不能违背运算符原来的含义(就算语法正确)

  • 注意点:

    • . ,.* ,?:,:: 不能被重载
#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
	MM() {}
	MM(string name, int score) :name(name), score(score) {}
protected:
	string name;
	int score;
};
int main() 
{
	int a = 1;
	int b = 2;
	int sum = a + b;
	MM mm("小芳", 6);
	MM girl("小芳", 2);
	//error: 没有与这些操作数匹配 "xxx" 运算符
	//MM result = mm + girl;			//错误
	return 0;
}

重载写法

重载函数的写法


//函数定义方式
函数返回值类型  函数名(参数)
{
	 //函数体;    
}
//运算符重载也是函数,只是函数名写法不同
//函数名: operator加上运算符组成函数名
//参数:
//		友元重载: 参数个数等于操作数
//		类成员函数: 参数个数等于操作-1
//		函数返回值类型:运算符组成表达式 最终结果是什么类型就返回类型
// 		int a; int b;  a+b 返回int
// 函数体:写你真正要实现的效果

友元重载

#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
	MM() {}
	MM(string name, int score) :name(name), score(score) {}
	void print() 
	{
		cout << name << "\t" << score << endl;
	}
	//友元重载
	friend MM operator+(MM a, MM b);		//加法重载函数的声明
protected:
	string name;
	int score;
};
MM operator+(MM a, MM b) 
{
	return MM(a.name, a.score+b.score);  //返回一个匿名对象
}
int main() 
{
	int a = 1;
	int b = 2;
	int sum = a + b;
	MM mm("小芳", 6);
	MM girl("小芳", 2);
	//error: 没有与这些操作数匹配 "xxx" 运算符
	//重载函数的隐式调用 -->mm + girl 解析为:operator+(mm, girl)
	MM result = mm + girl;				  //显示绿色就是运算符重载
	result.print();
	//重载函数显示调用:按照函数的调用方式
	MM res = operator+(mm, girl);		  //operator+:函数名  参数
	//string aa("12");
	//string bb("2323");
	//cout << (aa > bb) << endl;

	return 0;
}

类重载

#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
	MM() {}
	MM(string name, int score) :name(name), score(score) {}
	void print() 
	{
		cout << name << "\t" << score << endl;
	}
	//友元重载
	friend MM operator+(MM a, MM b);		//加法重载函数的声明
protected:
	string name;
	int score;
};
//类成员函数少一个参数: 对象本身可以表示参数
MM MM::operator-(MM object)
{
	return MM(this->name, this->score - object.score);
}

int main() 
{
	MM mul = mm.operator-(girl);		  //类重载显示调用,跟调用普通成员函数一样的
	mul.print();
	MM girlFriend = mm - girl;			  //编译器mm - girl翻译为: mm.operator-(girl)
	girlFriend.print();


	return 0;
}

特殊运算符重载

  • 通常情况:单目运算符用类成员函数重载,双目用友元重载
  • = ,(),->,[] 只能采用成员函数重载
  • ++ --运算符重载
    • 增加一个无用参数,标识是后置++或者--
  • 流运算符重载(>> <<)
    • 输入流对象(cin): istream类
    • 输出流对象(cout): ostream类
    • 流重载必须用引用
    • 流重载一定要用友元重载
  • 后缀重载
#include <iostream>
#include <string>
#include <thread>
using namespace std;
class MM 
{
public:
	MM() {}
	MM(string name, int age) :name(name), age(age) {}
	void print() 
	{
		cout << name << "\t" << age << endl;
	}
	//MM operator=(MM) = delete;		//删掉默认的
	//函数重载
	void operator=(int data) 
	{
		this->age += data;
	}
	//++ 为例
	MM operator++()						//前置
	{
		this->age++;
		return *this;					//返回对象本身
	}
	MM operator++(int)					//后置的
	{
		return MM(this->name, this->age++);
	}
	//流运算符的重载
	friend ostream& operator<<(ostream& out, MM& object);
	friend istream& operator>>(istream& in, MM& object);

private:
	string name;
	int age;
};
ostream& operator<<(ostream& out, MM& object) 
{
	//out当做cout用
	out << object.name << "\t" << object.age << endl;
	return out;
}
istream& operator>>(istream& in, MM& object) 
{
	cout << "输入对象属性:";
	//in当做cin用即可
	in >> object.name >> object.age;
	return in;
}
//文本重载, 一般写成下划线系列
//后缀的重载
unsigned long long operator""_h(unsigned long long data) 
{
	return data * 60 * 60;
}
unsigned long long operator""_m(unsigned long long data)
{
	return data * 60;
}
unsigned long long operator""_s(unsigned long long data)
{
	return data;
}
int main() 
{
	MM mm("小芳", 18);
	MM girl;
	girl = mm;				//每一个类中都存在默认的赋值重载
	girl = 8;
	girl.print();
	MM result = ++girl;
	result.print();
	girl.print();
	result = girl++;
	result.print();
	girl.print();
	cin >> girl;
	cout << girl << endl;	

	//this_thread::sleep_for(10s);
	cout << 1_h << endl;
	cout << (1_h + 30_m + 49_s) << endl;
	return 0;
}

对象的隐式转换

对象隐式转换: 就是让对象能够赋值给普通数据

//operator  转换的类型()
//{ 
//	return 要转换类型的数据;
//}
#include <string>
#include <iostream>
using namespace std;
class MM 
{
public:
	MM() {}
	MM(string name, int age) :name(name), age(age) {}
	operator int() 
	{
		return this->age;
	}
protected:
	string name;
	int age;
};
int main() 
{
	MM mm("mm", 39);
	int age = mm;
	cout << age << endl;

	return 0;
}

()运算符的重载

仿函数

让类型可以模仿函数调用的行为: 函数名(参数); 类名() 调用的函数行为

#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;

class Data 
{
public:
	//operator()组成函数名
	void operator()() 
	{
		cout << "无参重载()" << endl;
	}
	void operator()(int a, int b) 
	{
		cout << "有参重载(a,b)" << endl;
	}
protected:

};
int main() 
{
	//greater<int>();  //比较准则
	//int array[5] = { 3,4,1,2,32 };
	//sort(array, array + 5, greater<int>());
	//for (auto& v : array) 
	//{
	//	cout << v << "\t";
	//}
	//cout << endl;
	Data data;
	data.operator()();		//显式调用
	data.operator()(1, 2);	//显式调用
	data();					//隐式调用
	data(1, 2);				//隐式调用
	Data{}();				//{}帮助识别  Data()
	Data{}(2, 3);
	return 0;
}

运算符重载案例分析

智能指针

智能指针是用对象方式管理new的内存,可以做到自动释放(本质是析构函数自动调用)内存的功能

#include <iostream>
#include <memory>
using namespace std;
class Auto_Ptr 
{
public:
	Auto_Ptr(int* ptr) :ptr(ptr) {}
	~Auto_Ptr() 
	{
		if (ptr) 
		{
			delete ptr;
			ptr = nullptr;
		}
	}
	//访问指针
	int* operator->() 
	{
		return this->ptr;
	}
	//访问数据
	int& operator*() 
	{
		return *ptr;
	}
	//禁止拷贝,禁止赋值
	Auto_Ptr(Auto_Ptr&) = delete;
	Auto_Ptr& operator=(Auto_Ptr&) = delete;
protected:
	int* ptr;
};
int main() 
{
	Auto_Ptr object(new int(1999));
	cout << *object << endl;
	//shared_ptr<int>  p(new int(19999));
	//cout << *p << endl;
	//shared_ptr<double>  p2(new double(19.99));
	//cout << *p2 << endl;
	return 0;
}

封装数组

#include <iostream>
#include <vector>			//动态数组
using namespace std;
class my_vector 
{
public:
	my_vector(int capacity = 10) :capacity(capacity) 
	{
		mem = new int[capacity] {0};
		curSize = 0;
	}
	void push_back(int data) 
	{
		mem[curSize++] = data;
	}
	int* begin() 
	{
		return mem + 0;
	}
	int* end() 
	{
		return mem + capacity;
	}
	int& operator[](int index) 
	{
		if (curSize < index)
			curSize = index;
		return mem[index];
	}
	//万金油函数
	int size() 
	{
		return curSize;
	}
	int empty() 
	{
		return curSize == 0;
	}
	~my_vector() 
	{
		if (mem) 
		{
			delete[] mem;
			mem = nullptr;
		}
	}
protected:
	int* mem;
	int capacity;
	int curSize;
};

int main() 
{
	my_vector vec;
	for (int i = 0; i < 3; i++) 
	{
		vec[i] = i;
	}
	for (auto v : vec) 
	{
		cout << v << "\t";
	}
	cout << endl;
	cout << vec.size() << endl;
	for (int i = 0; i < vec.size(); i++) 
	{
		cout << vec[i] << "\t";
	}
	cout << endl;


	return 0;
}

迭代器实现

//迭代器就是让一个类中类去遍历数据

#include <iostream>
#include <string>
using namespace std;
struct Node 
{
	int data;
	Node* next;
	Node() :next(nullptr){}
	Node(int data) :data(data), next(nullptr) {}
	Node(int data, Node* next) :data(data), next(next) {}
};
class List 
{
public:
	List() :headNode(new Node),curSize(0){}
	void push_front(int data) 
	{
		headNode->next = new Node(data, headNode->next);
		curSize++;
	}
	Node* begin() 
	{
		return headNode->next;
	}
	Node* end() 
	{
		return nullptr;
	}
	class iterator 
	{
	public:
		iterator() :pmove(nullptr) {}
		void operator=(Node* pmove) 
		{
			this->pmove = pmove;
		}
		bool operator!=(Node* pmove) 
		{
			return this->pmove != pmove;
		}
		iterator operator++() 
		{
			this->pmove = this->pmove->next;	//链表++不了
			return *this;
		}
		int operator*() 
		{
			return this->pmove->data;			//*运算访问数据
		}
	private:
		Node* pmove;			//需要指针访问数据
	};

protected:
	Node* headNode;
	int curSize;
};
void my_list() 
{
	List list;
	for (int i = 0; i < 3; i++) 
	{
		list.push_front(i);
	}
	List::iterator it;
	for (it = list.begin(); it != list.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main() 
{
	string str = "ILoveyou";
	for (int i = 0; i < str.size(); i++) 
	{
		cout << str[i];
	}
	cout << endl;
	//类中类访问一个容器数据
	string::iterator it;
	for (it = str.begin(); it != str.end(); it++) 
	{
		cout << *it;		//*指针取值运算
	}
	cout << endl;
	//cout << *str.end() << endl;

	my_list();
	return 0;
}

重载的特殊问题

//对象与常量运算
#include <iostream>
#include <string>
using namespace std;
class Data 
{
public:
	Data() {}
	Data(int num) :num(num) {}
	//friend Data operator+(Data data, int num);
	//friend Data operator+( int num, Data data);
	//Data operator+(Data data) 
	//{
	//	return Data(this->num + data.num);
	//}
	void print() 
	{
		cout << num << endl;
	}
	friend Data operator+(Data data1, Data data2);
protected:
	int num;
};
//Data operator+(Data data, int num) 
//{
//	return Data(data.num + num);
//}
//Data operator+(int num, Data data) 
//{
//	return Data(num + data.num);
//}
Data operator+(Data data1, Data data2) 
{
	return Data(data1.num + data2.num);
}
int main() 
{
	Data data(1);
	Data temp;
	//data.成员函数(1);
	temp = data + 1;
	//1+data : 1.成员函数()
	temp = 1 + data;   //类成员函数没办法完成
	temp.print();
	return 0;
}