运算符重载之友元运算符重载

友元可以参考:https://blog.csdn.net/aaqian1/article/details/84427884

友元运算符重载函数: 把运算符重载函数定义为某个类的友元函数。

1、定义友元运算符重载函数的语法形式

(1)在类的内部,定义友元运算符重载函数的格式如下:

friend 函数类型 operator 运算符(形参表)
{
	函数体
}

(2)友元运算符重载函数也可以在类中声明友元函数的原型,在类外定义。
在类中,声明友元运算符重载函数原型的格式:

class X{
	friend 函数类型 operator 运算符(形参表);
}

在类外,定义友元运算符重载函数的格式如下:

函数类型 operator 运算符(形参表){
	函数体 
}

由于友元运算符重载函数不是该类的成员函数,所以在类外定义时不需要缀上类名。
若友元运算符重载函数重载的是双目运算符,则参数表中有两个操作数;若重载的是单目运算符,则参数表中只有一个操作数。

2、双目运算符重载

例 1:用友元运算符重载函数进行复数运算。

两个复数 a+bi 和 c+di 进行加、减、乘、除的方法如下:
加法:(a+bi)+(c+di)=(a+b)+(c+d)i
减法:(a+bi)-(c+di)=(a-b)+(c-d)i
乘法:(a+bi) * (c+di)=(ac-bd)+(ad+bc)i
除法:(a+bi) / (c+di)=(a+bi) * (c-di) / (cc+dd)
  在 C++ 中,不能直接进行复数的加、减、乘、除运算,不过可以定义四个友元运算符重载函数,通过重载“+、-、*、/ ”运算符来实现复数运算。
代码如下:

#include
using namespace std;
class Complex{
	private:
		double real;    //复数实部 
		double imag;	//复数虚部 
	public:
		Complex(double r=0.0,double i=0.0); //https://blog.csdn.net/aaqian1/article/details/83894795。带默认参数的构造函数 
		void print();
		friend Complex operator+(Complex& a,Complex& b);	//声明运算符,重载函数
		friend Complex operator-(Complex& a,Complex& b);	//声明运算符,重载函数
		friend Complex operator*(Complex& a,Complex& b);	//声明运算符,重载函数
		friend Complex operator/(Complex& a,Complex& b);	//声明运算符,重载函数
};
Complex::Complex(double r,double i){	//构造函数 
	real=r;
	imag=i;
} 
Complex operator+(Complex& a,Complex& b){
	Complex temp;
	temp.real=a.real+b.real;
	temp.imag=a.imag+b.imag;
	return temp;
}
Complex operator-(Complex& a,Complex& b){
	Complex temp;
	temp.real=a.real-b.real;
	temp.imag=a.imag-b.imag;
	return temp;
}
Complex operator*(Complex& a,Complex& b){
	Complex temp;
	temp.real=a.real*b.real-a.imag*b.imag;
	temp.imag=a.real*b.imag+a.imag*b.real;
	return temp; 
}
Complex operator/(Complex& a,Complex& b){
	Complex temp;
	double t;
	t=1/(b.real*b.real+a.imag*b.imag);
	temp.real=(a.real*b.real+a.imag*b.imag)*t;
	temp.imag=(b.real*a.imag-a.real*b.imag)*t;
	return temp;
}
void Complex::print(){	//显示输出复数 
	cout<<real;
	if(imag>0)
		cout<<"+";
	if(imag!=0)
		cout<<imag<<'i'<<endl;
}
int main(){
	Complex A1(2.3,1),A2(3.6,2.8),A3,A4,A5,A6;
	A3=A1+A2;
	A4=A1-A2;
	A5=A1*A2;
	A6=A1/A2;
	A3.print();
	A4.print();
	A5.print();
	A6.print();
	return 0;
}

执行结果如下:
运算符重载之友元运算符重载_第1张图片
  一般而言,如果在类 X 中采用友元函数重载双目运算符 @ ,而 aa 和 bb 是类 X 的两个对象,则以下两种函数调用方法是等价的:

aa@bb;		//隐式调用
operator@(aa,bb);		//显示调用

说明:
(1)有时,在函数返回的时候,可直接用类的构造函数来生成一个临时对象,而不对该对象进行命名,如可将例 1 中的重载运算符“ + ”的友元运算符重载函数

Complex operator+(Complex& a,Complex& b){
	Complex temp;
	temp.real=a.real+b.real;
	temp.imag=a.imag+b.imag;
	return temp;
}

改为:

Complex operator+(Complex& a,Complex& b){
	return Complex(a.real+b.real,a.imag+b.imag);
}

其中 return 语句中的

Complex(a.real+b.real,a.imag+b.imag);

是建立的一个临时对象,它没有对象名,是一个无名对象。在建立临时对象过程中调用构造函数。return 语句将此临时对象作为函数返回值。
这种方法的执行的效率比较高,但是前一种方法的可读性比较好。
(2)有的 C++ 系统(如 Visual C++ 6.0)没有完全实现 C++ 标准,它所提供的不带后缀的“ .h ”的头文件不支持友元运算符重载函数,在 Visual C++ 6.0 中编译会出错,这时可采用带后缀的“ .h ”头文件。将程序中的

#include
using namespace std;

改为

#include

即可顺利运行。

3、单目运算符重载

  单目运算符只有一个操作数,如 -a、&b、!c、++p等。

例 2:用友元函数重载单目运算符“-”

#include
using namespace std;
class Coord{
	private:
		int x,y;
	public:
		Coord(int x1=0,int y1=0){
			x=x1;
			y=y1;
		}
		friend Coord operator-(Coord &obj);	//声明为单目运算符 "-" 重载函数
		void print(); 
};
Coord operator-(Coord &obj){	//定义单目运算符 "-" 重载函数
	obj.x=-obj.x;
	obj.y=-obj.y;
	return obj;
}
void Coord::print(){
	cout<<"x="<<x<<"y="<<y<<endl;
}
int main(){
	Coord ob1(50,60),ob2;
	ob1.print();
	ob2=-ob1;
	ob2.print();
	return 0;
}

输出结果:
运算符重载之友元运算符重载_第2张图片

例 3:用友元函数重载单目运算符“++”

#include
using namespace std;
class Coord{
	private:
		int x,y;
	public:
		Coord(int x1=0,int y1=0){
			x=x1;
			y=y1;
		}
		friend Coord operator++(Coord &obj);	//声明为单目运算符 "-" 重载函数
		void print(); 
};
Coord operator++(Coord &obj){	//定义单目运算符 "-" 重载函数
	++obj.x;
	++obj.y;
	return obj;
}
void Coord::print(){
	cout<<"x="<<x<<";y="<<y<<endl;
}
int main(){
	Coord ob1(50,60);
	ob1.print();
	++ob1;
	ob1.print();
	operator++(ob1);
	ob1.print();
	return 0;
}

运算符重载之友元运算符重载_第3张图片
如果将友元运算符重载函数定义为以下格式:

friend Coord operator++(Coord op){	
	++obj.x;
	++obj.y;
	return obj;
}

运算符重载之友元运算符重载_第4张图片
  这个运行结果是错误的,原因是这个函数的形参是对象,是通过传值的方法传递参数的,函数体内对形参 obj 的所有修改都无法传到函数体外。即,实际上 operator++ 函数中 obj.x 和 obj.y 的增加并没有引起实参 ob1.x 和 ob1.y 的增加,因此造成了运行结果的错误。
  而形参是对象的引用时,是通过传址的方式传递参数的,函数形参 obj.x 和 obj.y 的改变将引起实参 ob1 的变化。

  一般而言,如果在类 X 中采用友元函数重载单目运算符 @ ,而 aa 是类 X 的两个对象,则以下两种函数调用方法是等价的:

@aa;	//隐式调用
operator@(aa);		//显式调用

说明:
(1)运算符重载函数 operator@ 可以返回任何类型,甚至可以是 void 类型,但通常返回的类型与它操作的类的类型相同,这样可以使重载运算符用在复杂的表达式中。
(2)有的运算符不能定义为友元运算符重载函数,如赋值运算符 “=”,下标运算符“[ ]”、函数调用运算符“ () ”等。

你可能感兴趣的:(c++)