zoukankan      html  css  js  c++  java
  • 运算符重载

    概述


     

    C++运算符重载是一个难点,今天复习整理一下该部分内容!

    说到运算符重载,第一个必须知道的是哪些运算符可以被重载,哪些运算符不能被重载!

    运算符优先级


     

    优先级操作符描述例子结合性
    1 ()
    []
    ->
    .
    ::
    ++
    --
    调节优先级的括号操作符
    数组下标访问操作符
    通过指向对象的指针访问成员的操作符
    通过对象本身访问成员的操作符
    作用域操作符
    后置自增操作符
    后置自减操作符
    (a + b) / 4;
    array[4] = 2;
    ptr->age = 34;
    obj.age = 34;
    Class::age = 2;
    for( i = 0; i < 10; i++ ) ...
    for( i = 10; i > 0; i-- ) ...
    从左到右
    2 !
    ~
    ++
    --
    -
    +
    *
    &
    (type)
    sizeof
    逻辑取反操作符
    按位取反(按位取补) 
    前置自增操作符
    前置自减操作符
    一元取负操作符
    一元取正操作符
    解引用操作符
    取地址操作符
    类型转换操作符
    返回对象占用的字节数操作符
    if( !done ) ...
    flags = ~flags;
    for( i = 0; i < 10; ++i ) ...
    for( i = 10; i > 0; --i ) ...
    int i = -1;
    int i = +1;
    data = *ptr;
    address = &obj;
    int i = (int) floatNum;
    int size = sizeof(floatNum);
    从右到左
    3 ->*
    .*
    在指针上通过指向成员的指针访问成员的操作符
    在对象上通过指向成员的指针访问成员的操作符
    ptr->*var = 24;
    obj.*var = 24;
    从左到右
    4 *
    /
    %
    乘法操作符
    除法操作符
    取余数操作符
    int i = 2 * 4;
    float f = 10 / 3;
    int rem = 4 % 3;
    从左到右
    5 +
    -
    加法操作符
    减法操作符
    int i = 2 + 3;
    int i = 5 - 1;
    从左到右
    6 <<
    >>
    按位左移操作符
    按位右移操作符
    int flags = 33 << 1;
    int flags = 33 >> 1;
    从左到右
    7 <
    <=
    >
    >=
    小于比较操作符
    小于或等于比较操作符
    大于比较操作符
    大于或等于比较操作符
    if( i < 42 ) ...
    if( i <= 42 ) ...
    if( i > 42 ) ...
    if( i >= 42 ) ...
    从左到右
    8 ==
    !=
    等于比较操作符
    不等于比较操作符
    if( i == 42 ) ...
    if( i != 42 ) ...
    从左到右
    9 & 按位与操作符 flags = flags & 42; 从左到右
    10 ^ 按位异或操作符 flags = flags ^ 42; 从左到右
    11 | 按位或操作符 flags = flags | 42; 从左到右
    12 && 逻辑与操作符 if( conditionA && conditionB ) ... 从左到右
    13 || 逻辑或操作符 if( conditionA || conditionB ) ... 从左到右
    14 ? : 三元条件操作符 int i = (a > b) ? a : b; 从右到左
    15 =
    +=
    -=
    *=
    /=
    %=
    &=
    ^=
    |=
    <<=
    >>=
    赋值操作符
    复合赋值操作符(加法)
    复合赋值操作符(减法)
    复合赋值操作符(乘法)
    复合赋值操作符(除法)
    复合赋值操作符(取余)
    复合赋值操作符(按位与)
    复合赋值操作符(按位异或)
    复合赋值操作符(按位或)
    复合赋值操作符(按位左移)
    复合赋值操作符(按位右移)
    int a = b;
    a += 3;
    b -= 4;
    a *= 5;
    a /= 2;
    a %= 3;
    flags &= new_flags;
    flags ^= new_flags;
    flags |= new_flags;
    flags <<= 2;
    flags >>= 2;
    从右到左
    16 , 逗号操作符 for( i = 0, j = 0; i < 10; i++, j++ ) ... 从左到右

    不能被重载的运算符


    C++中只能对已有的C++运算符进行重载,不允许用户自己定义新的运算符!

    C++中绝大部分的运算符可重载,除了成员访问运算符 . ,成员指针访问运算符 .* ,作用域运算符 :: ,长度运算符 sizeof 以及条件运算符 ?: ;

    这一点是需要我们切记的!

    运算符重载的方式


     

    这里的方式主要有两种,第一种:以友元(friend)函数的方式重载,第二种:以类成员函数的方式进行重载,这两种防水最终达到的效果是一样的,但是形式不一样。下面分别举例说明! 

    1)以友元(friend)函数的方式重载

      因为一般的类的数据成员都是私有的,因此,普通的全局函数无法访问类的私有数据成员,因此,必须是以友元函数的形式去访问类的数据成员!

    class Complex
    {
        Complex(double r = 0, double i =0): real(r), imag(i)
        {
            cout<<"Complex::Complex(double, double)"<<endl;
        }
    
        Complex(const Complex& p)
        {
            real = p.real;
            imag = p.imag;
            cout<<"Complex::Complex(const Complex&)"<<endl;
        }
    
        Complex& operator=(const Complex& p)
        {
            cout<<"Assignment Operator"<<endl;
            real = p.real;
            imag = p.imag;
            return *this;
        }
    
        friend Complex operator+(const Complex& com1, const Complex& com2)
        {
            return Complex(com1.real + com2.real, com1.imag + com2.imag);
        }
    
        friend Complex operator-(const Complex& com1, const Complex& com2)
        {
            return Complex(com1.real-com2.real, com1.imag-com2.imag);
        }
    
        friend void operator++(const Complex& com)
        {
            com.real++;
            com.imag++;
        }
    
    private:
        double real;
        double imag;
    };

      在这种方式当中,加法函数的参数有两个!

    2)以类成员函数的方式进行重载

    class Complex
    {
        Complex(double r = 0, double i =0): real(r), imag(i)
        {
            cout<<"Complex::Complex(double, double)"<<endl;
        }
    
        Complex(const Complex& p)
        {
            real = p.real;
            imag = p.imag;
            cout<<"Complex::Complex(const Complex&)"<<endl;
        }
    
        Complex& operator=(const Complex& p)
        {
            cout<<"Assignment Operator"<<endl;
            real = p.real;
            imag = p.imag;
            return *this;
        }
    
        Complex operator+(const Complex& com)
        {
            return Complex(real + com.real, imag + com.imag);
        }
    
        Complex operator-(const Complex& com)
        {
            return Complex(real-com.real, imag-com.imag);
        }
    
        void operator++()
        {
            real++;
            imag++;
        }
    
    private:
        double real;
        double imag;
    };

      在此种方式当中,无论是加法、减法还是自增函数,其函数参数都比前一种方式少一个参数,这是因此,以成员函数的方式进行重载时,可以利用 this 这个函数指针!

    几个特别运算符的重载


    因为在运算符当中,对于算术运算符,有单目运算符和双目运算符,在对其进行重载时,必须仔细实现!

    下面讲解几个特殊运算符的函数重载:

    1)>>

      提取运算符">>"也是如此,左操作数为istream类的对象,右操作数为基本类型数据。

      头文件 iostrem 对其重载的函数原型为 istream& operator>>(istream& ,类型名); 提取运算符也不能作为其他类的成员函数,可以是友元函数或普通函数。

      它的一般定义格式为:

      istream& operator>>(istream& ,自定义类名&);

    2)<<

      插入运算符"<<"是双目运算符,左操作数为输出流类ostream的对象,右操作数为系统预定义的基本类型数据。

      头文件 iostrem 对其重载的函数原型为 ostream& operator<<(ostream& ,类型名); 类型名就是指基本类型数据。但如果要输出用户自定义的类型数据的话,就需要重载操作符"<<",因为该操作符的左操作数一定为ostream类的对象,所以插入运算符"<<"只能是类的友元函数或普通函数,不能是其他类的成员函数

      一般定义格式:

      ostream& operator<<(ostream& ,自定义类名&);

    class Complex
    {
        Complex(double r = 0, double i =0): real(r), imag(i)
        {
            cout<<"Complex::Complex(double, double)"<<endl;
        }
    
        Complex(const Complex& p)
        {
            real = p.real;
            imag = p.imag;
            cout<<"Complex::Complex(const Complex&)"<<endl;
        }
    
        Complex& operator=(const Complex& p)
        {
            cout<<"Assignment Operator"<<endl;
            real = p.real;
            imag = p.imag;
            return *this;
        }
    
        friend std::ostream&operator<<(std::ostream& o,Complex& com);//友元函数重载提取运算符"<<"
        friend std::istream&operator>>(std::istream& i,Complex& com);//友元函数重载插入运算符">>"
    
    private:
        double real;
        double imag;
    };
    
    std::ostream&operator<<(std::ostream& o,Complex& com)
    {
        std::cout<<"输入的复数:";
        o<<com.real;
        if(com.imag>0)
            o<<"+";
        if(com.imag!=0)
            o<<com.imag<<"i"<<std::endl;
        return o;
    }
    
    std::istream&operator>>(std::istream& i,Complex& com)
    {
        std::cout<<"请输入一个复数:"<<std::endl;
        std::cout<<"real(实数):";
        i>>com.real;
        std::cout<<"imag(虚数):";
        i>>com.imag;
        return i;
    }

    3)++(前置与后置)

      其中,++(前置)返回的是自增后的对象,++(后置)返回的是自增前的对象!

    class TDPoint//三维坐标
    {
    private:
        int x;
        int y;
        int z;
    
    public:
        TDPoint(int x=0,int y=0,int z=0)
        {
            this->x=x;
            this->y=y;
            this->z=z;
        }
        
        TDPoint operator++();//成员函数重载前置运算符++
        TDPoint operator++(int);//成员函数重载后置运算符++
    
        friend TDPoint operator++(TDPoint& point);//友元函数重载前置运算符++
        friend TDPoint operator++(TDPoint& point,int);//友元函数重载后置运算符++
        void showPoint();
    };
    
    //////////////////////////////////////////////////////////////////////////
    //member function/////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    TDPoint TDPoint::operator++()
    {
        ++this->x;
        ++this->y;
        ++this->z;
        return *this;//返回自增后的对象
    }
    
    //////////////////////////////////////////////////////////////////////////
    //member function/////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    TDPoint TDPoint::operator++(int)
    {
        TDPoint point(*this);
        this->x++;
        this->y++;
        this->z++;
        return point;//返回自增前的对象
    }
     
    //////////////////////////////////////////////////////////////////////////
    //friend function/////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    TDPoint operator++(TDPoint& point)
    {
        ++point.x;
        ++point.y;
        ++point.z;
        return point;//返回自增后的对象
    }
             
    //////////////////////////////////////////////////////////////////////////
    //friend function/////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////
    TDPoint operator++(TDPoint& point, int)
    {
        TDPoint point1(point);
        point.x++;
        point.y++;
        point.z++;
        return point1;//返回自增前的对象
    }
    
    void TDPoint::showPoint()
    {
        std::cout<<"("<<x<<","<<y<<","<<z<<")"<<std::endl;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        TDPoint point(1,1,1);
        point.operator++();//或++point
        point.showPoint();//前置++运算结果
        
        point=point.operator++(0);//或point=point++
        point.showPoint();//后置++运算结果
        
        operator++(point);//或++point;
        point.showPoint();//前置++运算结果
        
        point=operator++(point,0);//或point=point++;
        point.showPoint();//后置++运算结果
         
        return 0;
    }

    下面汇总一下各种运算符重载的形式。


    关系运算符重载

    bool operator == (const A& ); 
    bool operator != (const A& );
    bool operator < (const A& );
    bool operator <= (const A& );
    bool operator > (const A& );
    bool operator >= (const A& );

    逻辑运算符重载

    bool operator || (const A& );
    bool operator && (const A& );
    bool operator ! ();

    单目运算符重载

    注意:这里的 + - 是正 负的意思,放在对象前面。

    A& operator + ();
    A& operator - ();
    A* operator & ();
    A& operator * ();

    自增自减运算符重载

    A& operator ++ ();//前置++
    A operator ++ (int);//后置++
    A& operator --();//前置--
    A operator -- (int);//后置--

    位运算符重载

    A operator | (const A& );
    A operator & (const A& );
    A operator ^ (const A& );
    A operator << (int i);
    A operator >> (int i);
    A operator ~ ();

    赋值运算符重载

    注意:没有 = 运算符

    A& operator += (const A& );
    A& operator -= (const A& ); 
    A& operator *= (const A& );
    A& operator /= (const A& );
    A& operator %= (const A& );
    A& operator &= (const A& );
    A& operator |= (const A& );
    A& operator ^= (const A& );
    A& operator <<= (int i);
    A& operator >>= (int i);

    内存运算符重载

    void *operator new(size_t size);
    void *operator new(size_t size, int i);
    void *operator new[](size_t size);
    void operator delete(void*p);
    void operator delete(void*p, int i, int j);
    void operator delete [](void* p);

    特殊运算符重载

    A& operator = (const A& );
    char operator [] (int i);//返回值不能作为左值
    const char* operator () ();
    T operator -> ();
    //类型转换符
    operator char* () const;
    operator int ();
    operator const char () const;
    operator short int () const;
    operator long long () const;
  • 相关阅读:
    RocketMQ中Producer消息的发送源码分析
    VS等待调试
    Window&Linux遍历某一文件夹
    遍历当前USB设备信息
    批处理常用符号详解
    Windows 批处理(bat)语法大全
    Windows CMD命令大全(值得收藏)
    遍历文件夹
    ASCII,UTF-8,Unicode字符串相互转换
    shellexecute的使用和X64判断
  • 原文地址:https://www.cnblogs.com/wiessharling/p/4179753.html
Copyright © 2011-2022 走看看