运算符重载
概述
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;