C++ 运算符重载

889 阅读6分钟

C++预定义的 + 、 - 、*、 / 、>、 >= 、<、 <= 、 == 、 != 等一系列运算符的操作对象只能是基本数据类型,要让它们在用户自定义的数据类型(如:类)中也能类似使用,就需要对运算符赋予多种含义,这就是运算符重载。

运算符重载的概念:对C++中的已有运算符赋予更多的含义,使之作用于特定类的对象,实现特定的功能,而且使用形式与基本数据类型的形式相同。

算符重载的理解: 运算符不变,重载只能考虑C++现有的运算符,不允许用户定义新的运算符;

操作数的范围有了变化,不再局限于基本数据类型,可以扩展到用户自定义的类型(即用户定义的类),所实现的功能也可以由用户来定义;

运算符的使用形式不变,这样用户就能充分利用已有的知识、经验,见“符”猜义,节省了学习时间,提高了工作效率。

运算符重载的一般规则

C++不允许用户自己定义新的运算符,只能对已有的运算符进行重载;
C++允许重载的运算符:(绝大多数运算符)
双目算术运算符: + 、 - 、*、 / 、 % (取模)
关系运算符: != 、 == 、>、 >= 、<、 <=
逻辑运算符:&&、 || 、!
单目运算符: + (正)、 - (负)、*(指针)、&(取地址)
自增自减运算符:++、--(又分为前缀、后缀)
位运算符: | 、&、~、^、 << (左移)、 >> (右移)
赋值运算符: = 、 += 、 -= 、 *= 、 /= 、 %= 、 |= 、 &= 、 ^= 、 <<= 、 >>=
空间申请与释放运算符:new、delete、new[]、delete[]
其它运算符:()(函数调用)、->(成员访问)、->*(成员指针访问)、,(逗号)、[](下标)

不能重载的运算符只有5个:
. (成员访问运算符)   	.* (成员指针访问运算符)
:: (域运算符) 		  sizeof(长度运算符)
? : (条件运算符)

重载不能改变运算符操作数的个数、优先级和结合性; 重载运算符的函数不能有默认的参数; 重载运算符必须和用户自定义类型的对象一起使用,其参数至少有一个是类对象或对象引用; 应当使重载运算符的功能类似于该运算符作用于标准数据类型时所实现的功能; 对于运算符: = (对象赋值)和 &(取对象地址)的功能,系统已有默认定义,通常情况用户不需要重新定义。只有当对象间赋值涉及动态分配的指针,有可能出现多个对象的指针指向同一位置时,用户才需要自己重新定义。

用成员函数重载运算符 主要是把握成员函数的类内声明、类外定义和函数调用等几个关键点: (1)运算符函数(即成员函数)的类内声明格式: 函数类型 operator 运算符([形参表]); (2)运算符函数(即成员函数)的类外定义格式: 函数类型 类名::operator 运算符([形参表]) { …… //对运算符的重载处理 } (3)运算符函数(即成员函数)的调用形式: 对象.operator 运算符([实参表]); 或 对象 运算符[操作数] //这种形式更常用

说明:

1、总是默认调用该成员函数的对象参与了其中的运算,因此,运算符函数隐含了一个参数,即this指针,它指向当前对象。所以,运算符函数的参数个数要比操作数的个数少一个,即双目运算符仅有一个参数,单目运算符无参数。请务必牢记这一点。

2、如果重载的运算符函数允许有参数,那么对该参数的类型并没有严格限定,既可以是自定义类型,也可以是基本数据类型。函数返回值类型的确定也是类似的;

3、运算符函数的调用方式有两种,一种是普通成员函数的调用方式,另一种是表达式的形式,但后一种方式更直观,更常用;

4、为了能在类外使用运算符表达式,通常把运算符函数设为public权限;

5、= 、()、[]、->等运算符只能用成员函数重载。

class Point{
public:
	int x;
	int y;
public:
	Point(int x = 0, int y = 0){
		this->x = x;
		this->y = y;
	}
	//成员函数,运算符重载
	Point operator+(Point &p2){
		Point tmp(this->x + p2.x, this->y + p2.y);
		return tmp;
	}
	void myprint(){
		cout << x << "," << y << endl;
	}
};

void main(){
	Point p1(10, 20);
	Point p2(20, 10);

	//运算符的重载,本质还是函数调用
	//p1.operator+(p2)
	Point p3 = p1 + p2;

	p3.myprint();

	system("pause");
}

C++.png

用友元函数重载运算符

友元函数作为被访问类的“好友”,它也有权访问被访问类的私有成员,因此,也可以用友元函数来重载运算符。 用友元函数方法重载运算符与之前介绍的用成员函数方法重载运算符相比, 相同点:调用方式一样,即: [操作数1] 运算符操作数2 不同点:由于友元函数不属于类的成员,不存在当前对象参与运算的问题,因此,该运算符函数的参数个数与操作数的个数一样多。

(1)运算符函数(即友元函数 )的类内声明格式:

friend 函数类型  operator 运算符(形参表);
//参数个数为一个或两个,不可能为空

(2)运算符函数(即友元函数)的类外定义格式:
//在函数名前不能加 类名和::符号
函数类型  operator 运算符(形参表)
{
	……  //对运算符的重载处理
}
(3)运算符函数(即友元函数)调用的基本形式:
操作数1  运算符  操作数2
//单目运算符只有一个操作数,++、--还有前缀、后缀之分

说明:
运算符函数参数的个数与操作数的个数相同,即双目运算符有两个参数,单目运算符只有一个参数,这一点很重要,再次强调一下;
运算符的使用只能采用:操作数1  运算符 操作数2的基本形式,不允许像上一节那样写成
对象.成员函数([实参表])  形式。
插入运算符( << )和提取运算符( >> )只能用友元函数方法进行重载。
//当属性私有时,通过友元函数完成运算符重载
class Point{
	friend Point operator+(Point &p1, Point &p2);
private:
	int x;
	int y;
public:
	Point(int x = 0, int y = 0){
		this->x = x;
		this->y = y;
	}
	void myprint(){
		cout << x << "," << y << endl;
	}
};

Point operator+(Point &p1, Point &p2){
	Point tmp(p1.x + p2.x, p1.y + p2.y);
	return tmp;
}

void main(){
	Point p1(10, 20);
	Point p2(20, 10);

	//运算符的重载,本质还是函数调用
	//p1.operator+(p2)
	Point p3 = p1 + p2;

	p3.myprint();

	system("pause");
}

C++.png