友元可以参考: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<iostream>
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;
}
执行结果如下:
一般而言,如果在类 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<iostream>
using namespace std;
改为
#include<iostream.h>
即可顺利运行。
3、单目运算符重载
单目运算符只有一个操作数,如 -a、&b、!c、++p等。
例 2:用友元函数重载单目运算符“-”
#include<iostream>
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;
}
输出结果:
例 3:用友元函数重载单目运算符“++”
#include<iostream>
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;
}
如果将友元运算符重载函数定义为以下格式:
friend Coord operator++(Coord op){
++obj.x;
++obj.y;
return obj;
}
这个运行结果是错误的,原因是这个函数的形参是对象,是通过传值的方法传递参数的,函数体内对形参 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)有的运算符不能定义为友元运算符重载函数,如赋值运算符 “=”,下标运算符“[ ]”、函数调用运算符“ () ”等。