欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

运算符重载

程序员文章站 2022-05-18 16:33:56
...

心得体会:如果不做特殊处理,C++的“+”“-”“*”“/”等等的运算符只能用于最基本的数的运算,而不能用于对象间的运算。如果可以将对象也进行这类操作,程序会更加的简洁,易懂。比如对两个复数对象进行计算。通过运算符的重载,赋予运算符新的功能,就能解决这类对象之间运算的问题。

运算符重载的概念和原理

可以重载的运算符

+   -   *   /   %   ^   &   |   ~

!   =   <   >   +=  -=  *=  /=  %

^=  &=  |=  <<  >>  >>= <<= ==  !=

<=  >=  &&  ||  ++  --  ->* ‘  ->

[]  ()  new delete  new[]   delete[]

不能重载的算符     

.     ::    .*    ?:    sizeof


重载运算符函数可以对运算符做出新的解释,但运算符重载后,原有的基本语义不变,包括:

(1)不改变运算符的优先级

(2)不改变运算符的结合性

(3)不改变运算符所需要的操作数

(4)不能创建新的运算符


一元运算符:

Object op 或 op Object

当重载为成员函数时,解释为:Object . operator op ()

操作数由对象Object通过this指针隐含传递

当重载为友元函数时,解释为:Operator op (Object)

操作数由参数表的参数Object提供

二元运算符:

Object op ObjectR

当重载为成员函数,解释为:

ObjectL operator op (ObjectR)

左操作数由ObjectL通过this指针传递,由操作数由函数ObjectR传递

当重载为友元函数,解释为:

operator op (ObjectL , ObjectR)

左右操作数都由参数传递


1. 运算符函数可以重载为成员函数友元函数 

①用成员函数重载运算符:

成员运算符函数的原型在类的内部声明格式如下:

class X {

    //…

返回类型 operator运算符(形参表);

  //…

}


类外定义成员运算符函数的格式如下:

返回类型 X::operator运算符(形参表)

{

     函数体

}

#include <bits/stdc++.h>
using namespace std;
class Complex
{
public:
    double real;
    double imag;
	Complex( ){
	    real=0,imag=0;
	    }
	Complex(double r,double i){
	    real=r;
	    imag=i;
	    }
	 Complex operator + (Complex &c2);
    void display( );
};
    Complex Complex:: operator + (Complex &c2) {
	return Complex(real+c2.real, imag+c2.imag);
	}
    void Complex::display( ){
	cout<<"("<<real<<","<<imag<<"i)"<<endl;
	}
    int main( ){
	Complex c1(3,4),c2(5,-10),c3;
	c3=c1+c2;
	cout<<"c1=";
	c1.display( );
	cout<<"c2=";
	c2.display( );
	cout<<"c1+c2 =";
	c3.display( );
	return 0;
}

②用友元函数重载运算符:

友元函数重载运算符常用于运算符的左右操作数类型不同的情况

①在第一个参数需要隐式转换的情形下,使用友元函数重载运算符是正确的选择
② 友元函数没有 this指针,所需操作数都必须在参数表显式声明,很容易实现类型的隐式转换
③C++中不能用友元函数重载的运算符有 =    ()    []   ->

 #include<bits/stdc++.h>
using namespace std;
class Complex
{
   double  Real,Image ;
   public:
   Complex( double r =0, double i =0 ) {
       Real = r;
       Image = i;
}
   Complex(int a) {
    Real = a;
    Image = 0;
}
   void print()const ;
   friend Complex operator + ( const Complex & c1, const Complex & c2 ) ;
   friend Complex operator - ( const Complex & c1, const Complex & c2 ) ;
   friend Complex operator - ( const Complex & c ) ;
};
   Complex operator + ( const Complex & c1, const Complex & c2 ){
       double r = c1.Real + c2.Real ;  double i = c1.Image+c2.Image ;
       return Complex ( r,  i ) ;
}
   Complex operator - ( const Complex & c1, const Complex & c2 ){
       double r = c1.Real - c2.Real ;  double i = c1.Image - c2.Image ;
       return Complex ( r,  i ) ;
}
   Complex operator - ( const Complex & c ){
       return Complex ( -c.Real, - c.Image );
}
void Complex :: print() const{
       cout << '(' << Real << " , " << Image << ')' << endl;
}
int main()
{
    
}

几个典型运算符重载

1.重载赋值运算符“=”

赋值运算符重载用于对象数据的复制 

operator=必须重载为成员函数

重载函数原型为:类名  类名  ::operator= ( 类名) ; 

赋值运算符“=”要求左右两个操作数的类型是匹配的,或至少是兼容的。有时希望“=”两边的操作数的类型即使不兼容也能够成立,这就需要对“=”进行重载

 #include<bits/stdc++.h>
using namespace std;
class String
{
    char* str;
    public:
    String():str(NULL){}//将stl初始化为NULL仅当执行了operator成员函数后,str才会指向动态分配的存储空间,并且从此后其值不可能再为NULL
    const char* c_str()const{return str;};//函数返回了指向String对象内部动态分配的存储空间的指针,但是不希望外部的到这个指针后修改其指向的字符串的内容,因此将返回类型设为const char*
    String & operator = (const char* s);
    ~String();
};
String&String::operator = (const char* s)
{
    if(str)//在String对象的生存期内,有可能从未执行过operator=成员函数,所以在析构函数中,执行delete【】str之前要先判断str是否为NULL
    delete [] str;
    if(s){
    str=new char[strlen(s)+1];
    strcpy(str,s);
    }
    else
    str=NULL;
    return* this;
}
String::~String()
{
    if(str)//在operator=函数中,要先判断str是否已经指向动态分配的存储空间,如果是,要先释放那片空间,然后重新分配一片空间,再将参数s指向的内容复制过去,这样,对象中存放的字符串就和s指向的字符串一样了
    delete [] str;
}
int main()
{
    String s;
    s="Good Morning,";
    cout<<s.c_str()<<endl;
    s="Mr.Shen";
    cout<<s.c_str()<<endl;
    return 0;
}
//如果没有对=进行重载,s="Good morning,"肯定会因为两边类型不匹配而编译出错

运算符重载

一般地,返回值是被赋值者的引用,即*this原因是

①这样在函数返回时避免一次拷贝,提高了效率。

②更重要的,这样可以实现连续赋值,即类似a=b=c这样。如果不是返回引用而是返回值类型,那么,执行a=b时,调用赋值运算符重载函数,在函数返回时,由于返回的是值类型,所以要对return后边的“东西”进行一次拷贝,得到一个未命名的副,然后将这个副本返回,而这个副本是右值,所以,执行a=b后,得到的是一个右值,再执行=c就会出错。

2.重载自增、自减运算符

运算符重载

成员函数重载++:

#include<iostream>
using namespace std;
class  Increase
{ public :
     Increase ( ) {value=0;}
     void  display( )const{cout<<value<<'\n';};
     Increase operator ++ ( ) ; 	     // 前置
     Increase operator ++ (int) ; 	     // 后置
  private:    
     unsigned  value ;
};
Increase Increase :: operator ++ ( ){ 
    value ++;   
    return *this; 
    }	
Increase Increase :: operator ++(int){ 
    Increase temp;
    temp.value = value ++;   
    return  temp; 
    }
int main( )
  { 
     Increase a,b,n;    
     int  i ;
     for (i=0 ;i<10;i++) a=n++;
     cout <<"n= ";  
     n.display( );   
     cout <<"a= ";   
     a.display( );
     for (i=0;i<10;i++)b=++n;
     cout<<"n=";   
     n.display( );   
     cout <<"b= ";   
     b.display( ) ;
 }

友元函数重载++:

#include<iostream>
using namespace std;
class  Increase
{ public :
     Increase(){value=0;}
     void display()const{cout<<value<<'\n';};
     friend Increase operator ++(Increase &);// 前置	
     friend Increase operator ++(Increase &,int);// 后置
  private:   
     unsigned value;
};
Increase operator ++(Increase &a)
{
    a.value ++;   
    return a; 
    }	
Increase  operator ++(Increase &a,int)
{ 
    Increase temp(a);
    a.value ++;   
    return  temp; 
    }
int main( )
{ 
    Increase a,b,n;    
    int i;
    for (i=0;i<10;i++)  
    a=n++;
    cout<<"n= ";  
    n.display();   
    cout<<"a= ";   
    a.display();
    for(i=0;i<10;i++)  
    b=++n;
    cout<<"n= ";  
    n.display();   
    cout<<"b=";   
    b.display();
 }

3.重载流插入和流提取运算符 

istreamostreamC++ 的预定义流类
cinistream的对象,coutostream的对象
运算符 <<ostream重载为插入操作,用于输出基本类型数据
运算符 >>istream重载为提取操作,用于输入基本类型数据
用友元函数重载 <<>> ,输出和输入用户自定义的数据类型 

重载输出运算符<<”(只能被重载成友元函数,不能重载成成员函数)

定义输出运算符“<<”重载函数的一般格式如下:

    ostream& operator<<(ostream& outclass_name&obj)

    {

         out<<obj.item1;

         out<<obj.item2;

         .. .

         out<<obj.itemn;

         return out;

    }

重载输入运算符“>>” (只能被重载成友元函数)

定义输入运算符函数 “>>”重载函数的一般格式如下:

    istream& operator>>(istream& inclass_name&obj)

    {

           in>>obj.item1;

           in>>obj.item2;

           . . .

          in>>obj.itemn;

          return in;

    }

#include <iostream>  
  
using namespace std;  
  
class Point  
  
{  
  
    int x,y;  
  
public:  
  
    friend istream & operator>>(istream & in, Point &p);  
  
    friend ostream & operator<<(ostream & out,const Point &p);  
  
};  
  
istream & operator>>(istream & in, Point &p)  
  
{  
  
    cout<<"Please input apoint:"<<endl;  
  
    in>>p.x;  
  
    in>>p.y;  
  
    return in;  
  
}  
  
ostream &operator<<(ostream & out,const Point &p)  
  
{  
  
    out<<"("<<p.x<< ","<<p.y <<")"<<endl;  
  
    return out;  
  
}  
  
int main()  
  
{  
  
    Point p;  
  
    cin>>p;  
  
    cout<<p;  
  
    return 0;  
  
}