运算符重载

来源:互联网 发布:雷军的编程能力 编辑:程序博客网 时间:2024/06/07 20:03
重载运算符可以把C++的运算符扩展到自定义类型和类类型的领域中,使代码更直观、易懂,方便、简洁。

目的:C++代码更直观,易读,使用更方便。
实质:运算符重载的实质是函数重载,只不过它重载的是类似“+ - * / =“ 这样的操作符。

运算符重载的限制

a、重载运算符时,重载运算符的运算顺序和优先级不变。
b、不能创造新运算符
c、规定不能重载的运算符:. 类属关系运算符 .* 成员指针运算符 :: 作用域运算符 ?: 条件运算符 # 编译预处理符号 sizeof() 取数据类型的长度

运算符重载的语法

两种形式:
a、重载为类的成员函数
函数类型 operator 运算符(形参表)
{    
     函数体;
}

b、重载为类的友元函数
friend 函数类型 operator 运算符(形参表)
{  
     函数体;
}

1.重载为类的成员函数:

一元运算符:++、-- 等
二元运算符:+、-、*、/、%  、=、+=、-=
#include <iostream>#include <iomanip>using namespace std ;class complex{public:        complex( double real = 0, double imag = 0):              r( real),i( imag){}        complex  operator +( complex&);        complex  operator -( complex&);        complex  operator +=(complex &);        void print()       {               cout << setiosflags(ios ::showpos )                      << r << " " << i << 'i' << endl;       }private:        double r, i;};complex complex ::operator +(complex & c )             {        return complex(r + c.r, i + c.i);}complex complex ::operator -(complex & c )              {        return complex(r - c.r,i - c.i);}complex complex ::operator + =(complex & c )           {        r += c.r;        i += c.i;        return *this;}void main ()                                    {        complex c1(1,1), c2(3,3), c3;        c3 = c1 + c2;                                 // 复数相加        c3. print();        c3 = c1 - c2;                                // 复数相减        c3. print();        c3 += c2 += c1;                          //复数相加后赋值        c3. print();}

说明:
a.二元运算符
对象本身*t h is 就是其中的一个操作数,另一个操作数由形参给出,通过运算符重载的函数进行传递;
b.一元运算符
操作数由对象的this 指针给出,就不再需要形参了。
一般来说,运算结果的类型与操作数的类型一致
在重载复数“+=” 运算符时,return 语句中的表达式是*this ,而其他运算符函数的return 语句的表达式是一个临时对象complex(r-c.r,i-c.i)。其实,将return *this 改为返回一个临时对象return complex(r,i) 结果是一样的,只是建立临时对象还要调用构造函数。返回*this 对象就不需要调用构造函数了,执行效率可以提高。

2.重载为类的友元函数:

运算符也可以重载为友元函数,这时运算所需要的操作数都需要通过形参来传递,形参从左到右的顺序就是运算符操作数的顺序。
#include <iostream>#include <iomanip>using namespace std ;class complex{public:        complex( double real=0, double imag=0):              r( real),i( imag){}        friend complex  operator+( complex&, complex&);        friend complex  operator -( complex&, complex&);        friend complex& operator +=(complex &,complex &);        void print()       {               cout<< setiosflags(ios ::showpos )                     <<r<< " "<<i<<'i' <<endl ;       }private:        double r, i;};complex operator +(complex & c1 ,complex & c2 ){        return complex( c1.r + c2.r, c1.i + c2.i);}complex operator -(complex & c1 ,complex & c2 ){        return complex( c1.r - c2.r, c1.i - c2.i);}complex& operator + =(complex & c1 ,complex & c2 )           {        c1.r += c2.r;        c1.i += c2.i;        return c1;}void main ()                                    {        complex c1(1,1), c2(3,3), c3;        c3 = c1 + c2;                                 // 复数相加        c3. print();        c3 = c1 - c2;                                // 复数相减        c3. print();        c3 += c2 += c1;                          //复数相加后赋值        c3. print();}

说明:
重载为友元函数,比如“+” ,操作数都由形参给出,通过运算符重载的函数进行传递。并且运算结果的类型与操作数的类型一致。
重载运算符的操作中,无论重载为成员函数还是友元函数,其形参多为引用类型,目的是增加可读性,提高程序的运行效率,因为使用引用类型,在进行参数传递的过程中,不需要复制临时对象


重载++和--运算符

在C++ 中有一类特殊的运算符,“++”、“--”运算符,这类运算符是一元运算符,它的运算规律因操作数的位置不同而不同。
++x  :前置自增算符,先自身增1 ,再将增加后的值作为表达式的值返回;
x++  :后置自增算符,先将本身的值作为表达式的值返回,自身再增1。
#include <iostream>using namespace std ;class weight{public:        weight( int v=0) : value( v) {}        // 前置自增        weight& operator ++();        // 后置自增        weight operator ++(int );        void print()       {               cout << value << endl;       }private:        int value;};// 前增量weight& weight ::operator ++(){       value++;        return * this;}// 后增量weight weight ::operator ++(int ){        weight temp(* this);    //操作数保存为临时对象       value++; // 操作数加1        return temp; // 返回没有加1的临时对象}void main (){        weight s1(1);        s1++. print(); //1        s1. print(); //2       (++ s1). print(); //3}

说明:
因为重载函数只能从形式参数上加以区别。
1、前置自增运算符
用成员函数实现时,没有形式参数。
2、后置自增运算符
另外增加一个形式上的形式参数,类型定为int。这个参数只是用来区别两种自增算符,并不参加实际的运算。

#include <iostream>using namespace std ;class weight{public:        weight( int v=0):value( v){}        friend weight& operator ++(weight &);        friend weight operator ++(weight &,int );        void print()       {               cout<<value<< endl;       }private:        int value;};weight& operator + +(weight & s ){        s.value++;        return s;}weight operator + +(weight & s ,int ){        weight temp( s);        s.value++;        return temp;}void main (){        weight s1(1);        s1++. print(); //1        s1. print(); //2       (++ s1). print(); //3}

重载赋值运算符

在C++ 中系统提供一个默认的重载的赋值运算符,所以同类的对象可以互相赋值。
缺省=运算符 和 缺省拷贝构造函数功能完全相同
例如:
RMB r1(20.3), r2;
RMB r3 = r1;             
r2 = r1;         
创建对象r3,调用的是拷贝构造函数,即用已有的对象创建新对象
r2 在赋值运算表达式中,对象已经存在,使用“=” 为对象赋值,调用的是赋值运算符。
一般来说,这个重载的赋值运算符可以直接使用,不需要自己定义。但是,在有些情况下,比如动态申请对内存的情况,则还是需要自己定义重载的赋值运算符。
#include <iostream>using namespace std ;class Name{public:        Name( char *str= NULL);        Name( Name &s);        Name& operator = ( Name&);        ~Name()       {               delete pName;       }        void print()       {               cout<<pName<< endl;       }private:        char *pName;};Name::Name (char *str ) {        if( str== NULL)              pName = NULL;        else{              pName= new char[ strlen( str)+1];               strcpy(pName, str);       }}Name& Name ::operator = (Name & s ){        if( this == & s) //需要判断其是否相等               return * this;        delete pName;       pName= new char[ strlen( s.pName)+1];        strcpy(pName, s.pName);        return * this;   }Name::Name (Name &s ){       pName= new char[ strlen( s.pName)+1];        strcpy(pName, s.pName);}void main (){        Name s1( "test = operator"),s2 ;        s2 = s1;        s2. print();}

说明:
由于在类的构造过程中动态申请了对内存,因此必须重载拷贝构造函数和赋值运算符。
a.拷贝构造函数在创建对象时调用,因为此时对象还不存在,只需要申请新的空间,而不需要释放原有资源空间。
b.赋值运算符在对象已存在的条件下调用,因此需要先释放原对象占用的空间,然后申请新的空间。


重载转换运算符

在C++ 中,数据类型转换对于基本数据类型有两种方式:隐式数据类转换 和 显式数据类型转换,也叫强制类型转换
对于自定义类型和类类型,类型转换操作是没有定义的。
强制类型转换使用“( )” 运算符完成,在C++ 中我们可以将“( )” 运算符进行重载,达到数据转换的目的。
转换运算符声明形式
operator 类型名 ();
特点:a.没有返回值 b.功能类似强制转换
#include <iostream>using namespace std ;class RMB{public:        RMB( double value = 0.0)       {              yuan = value;              fen = ( value - yuan) * 100 + 0.5;       }        void ShowRMB()       {               cout<<yuan<< "元"                     <<fen<< "分" <<endl ;       }        operator double ()                            {               return yuan + fen / 100.0;       }private:        int yuan, fen;};void main (){        RMB r1(1.01), r2(2.20);        RMB r3;        // 显式转换类型        r3 = RMB(( double) r1 + ( double) r2);        r3. ShowRMB(); // 3元21分        // 自动转换类型        r3 = r1 + 2.40;        r3. ShowRMB(); // 3元41分        // 自动转换类型        r3 = 2.0 - r1;        r3. ShowRMB(); // 0元99分}

对于r3=r1+2.40; 的系统工作:a.寻找重载的成员函数+运算符 b.寻找重载的友元函数+运算符 c.寻找转换运算符 d.验证转换后的类型是否支持+运算。
转换运算符重载一般建议尽量少使用

小结:
1.注意运算符重载的规则和限制
2.重载运算符的时候要注意函数的返回类型
2.前增量和后增量运算符的重载区别
4.赋值运算符重载要注意内存空间的释放和重新申请
5.转换运算符重载与构造函数、析构函数一样没有返回值,通过转换运算符重载可以在表达式中使用不同类型的对象,但要注意转换运算符重载不可滥用。