运算符重载

概述


 

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;

 

posted @ 2014-12-23 11:32  wiessharling  阅读(442)  评论(0编辑  收藏  举报