C++:运算符重载函数之友元运算符重载

news/2024/7/24 10:19:36 标签: c/c++

5.2.2 友元运算符重载函数

运算符重载函数一般采用两种形式定义:
一是定义为它将要操作的类的成员函数(简称运算符重载函数);
二是定义为类的友元函数(简称为友元运算符重载函数)。

1.定义友元运算符重载函数的语法如下:

复制代码
    在类的内部:  friend 函数类型 operator运算符(形参表)
                  {
                     函数体 
                   }      

    在类的内部声明,在类外定义:
                  class X{
                     ...
                     friend 函数类型 operator运算符(形参表); 
                  };
                  函数类型 X::operator运算符(形参表)
                  {
                     函数体 
                   }
复制代码

其中,X是友元函数的运算符重载函数所在类的类名;函数类型指定了友元运算符函数的返回值类型;operator是定义运算符重载函数的关键字;运算符即是要重载的运算符名称,必须是C++中可重载的运算符;形参表中给出重载运算符所需要的参数和类型;关键字friend表明这是一个友元运算符重载函数。由于友元运算符重载函数不是该类的成员函数,所以在类外定义时不必缀上类名。

注意:若友元运算符重载函数重载的是双目运算符,则参数表中有两个操作数;若友元运算符重载函数重载的是单目运算符,则参数表中只有一个操作数。 

例5.2 用友元运算符重载函数进行复数的运算。

加法:(a+bi)+(c+di)=(a+c)+(b+d)i
减法:(a-bi)+(c-di)=(a-c)+(b-d)i
乘法:(a-bi)*(c-di)=(ac-bd)+(ad+bc)i
除法:(a-bi)/(c-di)=(a+bi)*(c-di)/(c*c+d*d)

复制代码
#include<iostream>
using namespace std;
class Complex{
  public:
    Complex(){};
    Complex(double r,double i)
    {
     real = r;
     imag = i;
    }
    void print();
    friend Complex operator+(Complex &co1,Complex &co2);  //声明运算符+的重载函数 
    friend Complex operator-(Complex &co1,Complex &co2);  //声明运算符-的重载函数
    friend Complex operator*(Complex &co1,Complex &co2);  //声明运算符*的重载函数
    friend Complex operator/(Complex &co1,Complex &co2);  //声明运算符/的重载函数
  private:
    double real;//复数的实部 
    double imag;//复数的虚部 
};
Complex operator+(Complex &co1,Complex &co2)  //定义运算符+的重载函数 
{
 Complex temp;
 temp.real = co1.real+co2.real;
 temp.imag = co1.imag+co2.imag;
 return temp;   //return Complex(co1.real+co2.real,co1.imag+co2.imag) 
}
Complex operator-(Complex &co1,Complex &co2)  //定义运算符-的重载函数
{
 Complex temp;
 temp.real = co1.real-co2.real;
 temp.imag = co1.imag-co2.imag;
 return temp;  //return Complex(co1.real-co2.real,co1.imag-co2.imag)
}  
Complex operator*(Complex &co1,Complex &co2)  //定义运算符*的重载函数
{
 Complex temp;
 temp.real = co1.real*co2.real-co1.imag*co2.imag;
 temp.imag = co1.real*co2.imag+co1.imag*co2.real;
 return temp;
}
Complex operator/(Complex &co1,Complex &co2)  //定义运算符/的重载函数
{
 Complex temp;
 double t;
 t = 1/(co2.real*co2.real+co2.imag*co2.imag);
 temp.real = (co1.real*co2.real+co1.imag*co2.imag)*t;
 temp.imag = (co2.real*co1.imag-co1.real*co2.imag)*t;
 return temp;
} 
void Complex::print() 
{
 cout<<real;
 cout<<"+"<<imag<<'i'<<endl; 
} 
int main()
{
 Complex A1(2.3,4.6),A2(3.6,2.8),A3,A4,A5,A6;
 A3 = A1+A2; //A3 = operaotr+(A1,A2) 
 A4 = A1-A2; //A3 = operaotr-(A1,A2)
 A5 = A1*A2; //A3 = operaotr*(A1,A2)
 A6 = A1/A2; //A3 = operaotr/(A1,A2)
 A1.print();
 A2.print();
 A3.print();
 A4.print();
 A5.print();
 A6.print();
 return 0; 
} 
复制代码

说明:

(1) 一般而言,如果在类X中采用友元函数重载双目运算符@,而aa和bb是类的两个子类对象,则有以下两种函数调用方法是等价的。

复制代码
 aa@bb;                //隐式调用 
       operator@(aa,bb);     //显示调用
       
       例如:  A3 = A1+A2;  ============   A3 = operaotr+(A1,A2) 
              A4 = A1-A2;  ============   A4 = operaotr-(A1,A2)
              A5 = A1*A2;  ============   A5 = operaotr*(A1,A2)
              A6 = A1/A2;  ============   A6 = operaotr/(A1,A2) 
复制代码

(2)有时,在函数返回时候,可以直接在类的构造函数来生成一个临时对象,而不对该对象进行命名,例如将上述重载运算符+友元运算符重载函数

复制代码
 Complex operator+(Complex &co1,Complex &co2)  
            {
             Complex temp;
             temp.real = co1.real+co2.real;
             temp.imag = co1.imag+co2.imag;
             return temp;   
            }
        改为:
         Complex operator+(Complex &co1,Complex &co2)  
            {
             return Complex(co1.real-co2.real,co1.imag-co2.imag) //创建了一个临时的无名对象    
            }  
复制代码

(3)有的C++系统(如Visual C++6.0)没有完全实现C++标准,它所提供的不带后缀.h文件不支持友元运算符重载函数,在Visual C++6.0中编译错误,这是可以采用带后缀的“.h”头文件。

     即将 #include<iostream>
              using namespace std
              
         改为 #include<iostream.h>    

 

例5.2 用友元运算符重载函数进行复数的运算。
加法:(a+bi)+(c+di)=(a+c)+(b+d)i
减法:(a-bi)+(c-di)=(a-c)+(b-d)i
乘法:(a-bi)*(c-di)=(ac-bd)+(ad+bc)i
除法:(a-bi)/(c-di)=(a+bi)*(c-di)/(c*c+d*d)

复制代码
#include<iostream>
using namespace std;
class Complex{
  public:
    Complex(){};
    Complex(double r,double i)
    {
     real = r;
     imag = i;
    }
    void print();
    friend Complex operator+(Complex &co1,Complex &co2);  //声明运算符+的重载函数 
    friend Complex operator-(Complex &co1,Complex &co2);  //声明运算符-的重载函数
    friend Complex operator*(Complex &co1,Complex &co2);  //声明运算符*的重载函数
    friend Complex operator/(Complex &co1,Complex &co2);  //声明运算符/的重载函数
  private:
    double real;//复数的实部 
    double imag;//复数的虚部 
};
Complex operator+(Complex &co1,Complex &co2)  //定义运算符+的重载函数 
{
    return Complex(co1.real+co2.real,co1.imag+co2.imag); 
}
Complex operator-(Complex &co1,Complex &co2)  //定义运算符-的重载函数
{
    return Complex(co1.real-co2.real,co1.imag-co2.imag);
}  
Complex operator*(Complex &co1,Complex &co2)  //定义运算符*的重载函数
{
     return Complex(co1.real*co2.real-co1.imag*co2.imag,co1.real*co2.imag+co1.imag*co2.real);
}
Complex operator/(Complex &co1,Complex &co2)  //定义运算符/的重载函数
{
     double t;
     t = 1/(co2.real*co2.real+co2.imag*co2.imag);
     return Complex((co1.real*co2.real+co1.imag*co2.imag)*t,(co2.real*co1.imag-co1.real*co2.imag)*t);
} 
void Complex::print() 
{
 cout<<real;
 cout<<"+"<<imag<<'i'<<endl; 
} 
int main()
{
 Complex A1(2.3,4.6),A2(3.6,2.8),A3,A4,A5,A6;
 A3 = A1+A2; //A3 = operaotr+(A1,A2) 
 A4 = A1-A2; //A3 = operaotr-(A1,A2)
 A5 = A1*A2; //A3 = operaotr*(A1,A2)
 A6 = A1/A2; //A3 = operaotr/(A1,A2)
 A1.print();
 A2.print();
 A3.print();
 A4.print();
 A5.print();
 A6.print();
 return 0; 
} 
复制代码

3. (友元运算符重载函数中)单目运算符重载

单目运算符只有一个操作数,如-a,&b,!c,++p等。重载单目运算符的方法与重载双目运算符的方法类似的。

注意:有友元函数重载单目运算符时,需要一个显示的操作数。

//例 5.3 用友元函数重载单目运算符"-"

复制代码
#include<iostream>
using namespace std;
class Coord{
 public:
    Coord(int x=0,int y=0)
    {
      i = x;
      j = y;
    }
    void print()
    {
     cout<<"i="<<i<<",";
     cout<<"j="<<j<<endl;
    }
    friend Coord operator-(Coord a); //声明友元单目运算符-(负号)重载函数 
 private:
   int i;
   int j;
};
Coord operator-(Coord obj)            //定义友元单目运算符-(负号)重载函数
{
   obj.i = -obj.i;
   obj.j = -obj.j;
   return obj;     
} 
int main()
{
 Coord ob1(50,60),ob2;
 ob1.print();
 ob2 = -ob1;
 ob2.print();
 return 0;
}
复制代码

//例5.4 用友元函数重载单目运算符"++"

复制代码
#include<iostream>
using namespace std;
class Coord{
  public:
    Coord(int x=0,int y=0) 
    {
        i = x;
        j = y; 
    }
    friend Coord operator++(Coord &c) //定义友元运算符++"自加"的重载函数 
    {
      c.i++;
      c.j++;
      return c;   
    }
    void print()
    {
     cout<<"i="<<i<<","<<"j="<<j<<endl; 
    }
  private:
    int i;
    int j;
}; 
int main()
{
 Coord ob1(10,20),ob2;
 ob1.print(); 
 
 ++ob1;           //隐式调用友元运算符重载函数 
 ob1.print();
 
 operator++(ob1); //显式调用友元运算符重载函数 
 ob1.print();
 
 ob2=++ob1;                //隐式调用友元运算符重载函数
 ob1.print();
 
 ob2=operator++(ob1);      //显式调用友元运算符重载函数
 ob2.print();
 
 return 0; 
}
复制代码

注意: 
使用友元运算符重载单目运算符"++"时,形参是对象的引用,是通过传址的方法传递参数的,函数形参op.x和op.y的改变将引起实参op.x和op.y的变化。

但是,如果形参是对象的话,是通过值传递的方法传递参数的,函数体内对形参op的所有修改都无法传递到函数体外。也就是说,实际上形参值的改变不能引起实参值的改变。


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

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

说明:
(1)运算符重载函数operator@可以是任何类型,甚至可以是void类型,但通常返回类型与所操作的类的类型相同,这样可以使重载运算符用在复杂的表达式中。

(2)有的运算符不能定义为友元运算符重载函数,如赋值运算符"="、下标运算符[]、函数调用运算符"()"等。

 

程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!
本文转自当天真遇到现实博客园博客,原文链接:http://www.cnblogs.com/XYQ-208910/p/4912514.html ,如需转载请自行联系原作者

http://www.niftyadmin.cn/n/978851.html

相关文章

第3章 敏捷项目管理概述

第3章 敏捷项目管理概述 3.1 敏捷项目管理架构 1.敏捷项目管理架构概述 敏捷项目管理架构(Agile Project Management Framework,APMF)&#xff0c;旨在协助团队聚焦于将项目的商业价值最大化&#xff0c;是基于价值分析和分解的项目管理&#xff0c;也就是价值驱动的项目管理。…

逆序数 UVALive 6508 Permutation Graphs

题目传送门 1 /*2 题意&#xff1a;给了两行的数字&#xff0c;相同的数字连线&#xff0c;问中间交点的个数3 逆序数&#xff1a;第一行保存每个数字的位置&#xff0c;第二行保存该数字在第一行的位置&#xff0c;接下来就是对它求逆序数4 用归并排序或线段树…

电脑运用技巧_运用一些简历技巧可以帮助您找到新工作

电脑运用技巧Data-driven resumes and some professional advice can make a big difference when you’re job hunting.求职时&#xff0c;数据驱动的简历和一些专业建议可能会产生很大的不同。 By Chandra Steele通过 钱德拉斯蒂尔 With so many people looking for jobs r…

搞V6记录

2019独角兽企业重金招聘Python工程师标准>>> 一、首先需要确定PC上是否有microsoft teredo tunneling驱动&#xff0c;查看方式&#xff0c;我的电脑右键>设备管理器>查看>显示隐藏的设备>网络适配器&#xff0c;如有则进行下一步&#xff0c;如果没有&…

CentOS 7 网卡命名修改为eth0格式

Linux 操作系统的网卡设备的传统命名方式是 eth0、eth1、eth2等&#xff0c;而 CentOS7 提供了不同的命名规则&#xff0c;默认是基于固件、拓扑、位置信息来分配。这样做的优点是命名全自动的、可预知的&#xff0c;缺点是比 eth0、wlan0 更难读&#xff0c;比如 ens33 。 一、…

JavaScript 浮点数陷阱及解法

JavaScript 浮点数陷阱及解法

Protospray可以将任何3D打印对象转换为触摸屏显示器

Dubbed as the ‘ProtoSpray’, the revolutionary new technology harnesses the power of 3D printing techniques and sprayable electronic technology. The researchers from the University of Bristol took inspiration from how an artist creates graffiti on a wall.…