运算符重载

运算符重载

重载函数的返回值和参数 一般是引用类型,为什么?点这里

  • 实质上是函数的重载。
  • 一般格式:函数类型 operator 运算符名称 (形参表列) { 对运算符的重载处理 }
Complex operator+(Complex &c2) {return Complex(real+c2.real, imag+c2.imag);}
Complex c1(3,4),c2(5,-10),c3;
c3 = c1 + c2;
实际上:c3 = c1.operator + (c2)
  • 运算符被重载后,其原有的功能仍然保留,没有丧失或改变。

  • 重载运算符的规则

    • C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。
    • C++中绝大部分的运算符允许重载。不能重载的运算符只有5个:
    .        (成员访问运算符)
    .*       (成员指针访问运算符)(域运算符)
    sizeof   (长度运算符)
    ?:       (条件运算符)
    
    • 前两个运算符不能重载是为了保证访问成员的功能不能被改变
    • 域运算符和sizeof运算符的运算对象是类型而不是变量或一般表达式,不具重载的特征。
    • 不能改变运算符运算对象(即操作数)的个数
    • 不能改变运算符的优先级别。
    • 不能改变运算符的结合性。
    • 不能有默认的参数,否则就改变了运算符参数的个数
    • 必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象的引用)。即参数不能全部是C++的标准类型,以防止用户修改用于标准类型数据的运算符的性质。
      +用于类对象的运算符一般必须重载,但有两个例外,运算符“=”和“&”不必用户重载。
      • 赋值运算符(=)可以用于每一个类对象,可以利用它在同类对象之间相互赋值。
      • 地址运算符&也不必重载,它能返回类对象在内存中的起始地址。
    • 应当使重载运算符的功能类似于该运算符作用于标准类型数据时所实现的功能。
    • 运算符重载函数可以是类的成员函数,类的友元函数,普通函数。
  • 运算符重载函数作为类成员函数

    • 实际上,运算符重载函数有两个参数,由于重载函数是Complex类中的成员函数,有一个参数是隐含的,运算符函数是用this指针隐式地访问类对象的成员。即最上面那个例子中
    Complex operator+(Complex &c2) 
    {
    return Complex(this.real+c2.real, this.imag+c2.imag);
    }
    
  • 运算符重载函数作为友元函数friend Complex operator + (Complex &c1,Complex &c2);//重载函数作为友元函数,此时有两个参数。调用时编译器对c1+c2的解释为:operator+(c1,c2)

  • 为什么把运算符函数作为友元函数呢?
    因为运算符函数要访问Complex类对象中的成员。如果运算符函数不是Complex类的友元函数,而是一个普通的函数,它是没有权利访问Complex类的私有成员的。

  • 成员函数方式 or 友元函数方式?

    • 如果将运算符重载函数作为成员函数,
      • 它可以通过this指针自由地访问本类的数据成员,因此可以少写一个函数的参数
      • 必须要求运算表达式第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算符函数的类型相同。如:Complex operator+(int &i){return Complex(real+i,imag);}c3=i+c2;则是错的。
    • 如果运算符左侧的操作数属于C++标准类型(如int)或是一个其他类的对象,则运算符重载函数**不能作为成员函数,**只能作为非成员函数。如果函数需要访问类的私有成员,则必须声明为友元函数。如:Complex operator+(int &i, Complex &c) return Complex(i+c.real,c.imag);} //运算符重载函数不是成员函数
  • 重载双目运算符

  • 双目运算符重载为友元函数时,在函数的形参表列中必须有两个参数,不能省略,形参的顺序任意,不要求第一个参数必须为类对象。但在使用运算符的表达式中,要求运算符左侧的操作数与函数第一个参数对应,运算符右侧的操作数与函数的第二个参数对应。如上面c3=i+c2; 是对的,c3=c2+i;则不对。

  • 赋值运算符、下标运算符、函数调用运算符等 必须定义为类的成员函数
  • 流插入“<<”和流提取运算符“>>”、类型转换运算符等 不能定义为类的成员函数

  • 一般将单目运算符重载为成员函数, 将双目运算符重载为友元函数

如果运算符函数重载为成员函数,它的第一个参数必须是本类的对象。当第一个操作数不是类对象时,不能将运算符函数重载为成员函数。如果将运算符“+”函数重载为类的成员函数,交换律不适用。

  • 重载单目运算符

    • 运算符重载函数只有一个参数,如果运算符重载函数作为成员函数,则还可省略此参数。
    • 自增运算符
      • Time operator++( ); //声明前置自增运算符“++”重载函数
      • Time operator++(int); //声明后置自增运算符“++”重载函数,增加一个int型形参,用来和前置自增运算符做出区别
    Time Time∷operator++( )                     //定义前置自增运算符“++”重载函数
    {if(++sec>=60)
    {sec-=60;
    ++minute;}
    return *this;                              //返回自加后的当前对象
    }
    Time Time∷operator++(int)                  //定义后置自增运算符“++”重载函数
    {
    Time temp(*this);
    sec++;
    if(sec>=60)
    {
    sec-=60;
    ++minute;
    }
    return temp;                                //返回的是自加前的对象
    }
    
  • 重载流输出运算符“<<”:friend ostream& operator <<(ostream&,Complex&);

  • 重载流插入运算符“<<”:friend istream& operator >>(istream&,Complex&);

ostream& operator << (ostream& output,Complex& c)       //定义运算符“<<”重载函数
{
output<<(<<c.real<<+<<c.imag<<″i)<<endl; //“<<”是C++预定义的流插入符,因为它右侧的操作数是字符串常量和double类型数据。
return output;//作用是能连续向输出流插入信息,比如 
}
int main( )
{
Complex c1(2,4),c2(6,10),c3;
c3=c1+c2;
cout<<c3;   //相当于 operator<<(cout,c3),是重载的流插入符
return 0;
}
调用函数时,形参output成为cout的引用,形参c成为c3的引用。即表示为:cout<<(<<c3.real<<+<<c3.imag<<″i)<<endl; return cout;
  • return output的作用是什么?
    • 能连续向输出流插入信息outputostream类的对象,它是实参cout的引用,也就是cout通过传送地址给output(或者说output是``cout的别名),使它们二者共享同一段存储单元。因此,return output就是return cout,将输出流cout的现状返回,即保留输出流的现状。cout< (cout<
  • 引用作为函数的形参可以在调用函数的过程中不是用传递值的方式进行虚实结合,而是通过传址方式使形参成为实参的别名,因此不生成临时变量(实参的副本),减少了时间和空间的开销。
  • 重载函数的返回值是对象的引用时,返回的不是常量,而是引用所代表的对象,它可以出现在赋值号的左侧而成为左值(left value),可以被赋值或参与其他操作(如保留cout流的当前值以便能连续使用“<<”输出)。
  • 使用引用时要特别小心,因为修改了引用就等于修改了它所代表的对象。


  • 不同类型数据间的转换

    • 标准类型数据间的转换:
      • 隐式类型转换
      • 显式类型转换:类型名(数据),将数据的类型转换为类型名的类型
    • 对用户自己声明的类型进行转换 ——>转换构造函数
  • 转换构造函数:将一个其他类型的数据转换成一个类的对象

    • 只有一个形参的构造函数,可以在函数体内指定转换的方式。
    • 可以将另一个类的对象转换成转换构造函数所在的类对象。
  • 类型转换函数:将一个类的对象转换成另一类型的数据

operator 类型名( )
{实现转换的语句}
operator double( ) {return real;}                //类型转换函数
==============
int main( )
{
Complex c1(3,4),c2(5,-10),c3;
double d;
d=2.5+c1;                           //要求将一个double数据与Complex类数据相加
cout<<d<<endl;
return 0;
}

假如程序中需要对一个Complex类对象和一个double型变量进行+,-,*,/等算术运算,以及关系运算和逻辑运算

  • 如果不用类型转换函数,就要对多种运算符进行重载,以便能进行各种运算。这样,是十分麻烦的,工作量较大,程序显得冗长。
  • 如果用类型转换函数对double进行重载(使Complex类对象转换为double型数据),就不必对各种运算符进行重载,因为Complex类对象可以被自动地转换为double型数据,而标准类型的数据的运算,是可以使用系统提供的各种运算符的。

你可能感兴趣的:(编程语言)