运算符与运算符函数
-
常见的运算符
单目运算符: 相反数:- 自变:++/-- 取地址:& Point a; 解引用:* 间接成员访问:-> 逻辑非:! 位反:~ 类型转换:() 函数:() 双目运算符: 算术运算符:+ - * / % 关系运算符:> >= < <= == != 逻辑运算符:&& || 位运算符:& | ^ << >> 下标运算符:[]
-
什么叫运算符重载?
在C++中编译器有能力把由运算符和数据组成的表达式解释成一个一全局函数或成员函数来调用,这种函数叫运算符函数,通过把运算符定义为函数,程序员可以自定义函数的运算规则,我们把自定义运算符函数规则的行为。在C++中编译器有能力把由运算符和数据组成的表达式解释成一个一全局函数或成员函数来调用,这种函数叫运算符函数,通过把运算符定义为函数,程序员可以自定义函数的运算规则,我们把自定义运算符函数规则的行为。
-
双目运算符重载
定义为成员函数 a+b-c == a.operator+(b).operator-(c) 定义为全局函数 a+b-c == operator-(operator+(a,b),c)
-
单目运算符重载
定义为成员函数 ~a = a.operator~() 定义为全局函数 ~a = operator~(a)
-
典型双目运算符重载
class Point { public: int x; int y; };
Point a,b;
Point c = a + b;
1、成员函数
Point& operator+(const Point& other);
2、全局函数
Point& operator+(const Point& a,const Point& b);
3、friend
使用friend关键字可以把一个全局函数,变成另一类的友元函数。 友元函数可以访问友元类中的所有成员,包括私有成员。
注意:友元不是成员,友元函数在调用时没有传递this指针,因此不能直接访问类中的成员,必须经过对象才能访问。
由于友元函数是全局的,与成员函数不在同一个作用域下,因此友元与成员不会构成重载。
-
输入输出运算符重载
cout(ostream)与cin(istream)是对标准库中创建的类对象,根据双目运行的格式(a#b == a.operator#(b)),如果对<< >>运算符进行重载不能写成成员函数,必须是全局或友元。
-
单目运算符重载
Point a;
++a;
1、成员函数
Point& operator++(void);
2、全局函数
Point& operator++(Point& _this);
1、下标操作 [] 一般用于容器型对象。
2、函数操作符 (),重载此运算符,对象可以当作函数使用。
3、解引用和间接成员访问运算符,*,->,重载此运算符,对象可以当作指针使用。
4、智能指针与auto_ptr
常规指针的缺点:一般一个指针变量离开它的作用域时,只有该指针所占用的内存空间才被释放(4字节或8字节),而指针所指向的内存空间不会释放。在某些特殊情况下,free/delete/delete[]可能调用不到,形成内存泄漏。
智能指针与常规指针的一致性:智能指针其实就是对象,是通过运算符重载(*,->),让对象与指针从用法上感觉一样。
智能指针与常规指针不一致性:任何时候,一个对象只能有一个智能指针持有它的地址,否则该对象会被多个智能指针析构多次,智能指针的拷贝构造和赋值构造需要做深拷贝处理。
auto_ptr的局限性:
不能跨作用域使用,不能放入标准容器中,不能指向对象数据。
5、new和delete运算符
在C++中new和delete虽然是关键字,但依然是运算符,因此可以重载,但一般一建议,在重载newdelete函数中,不需要显式调用构造和析构函数,编译器会自动生成调用代码。
-
运算符重载的限制
1、不能重载的运算符
作用域限定符(::) 直接成员访问运算符(.) 条件表达式运算符(?) 字节长度运算符(sizeof) 类型信息运算符(typeid)
2、基本类型的运算符无法重载
int a,b; a+b; int operator+(int&a ,int& b) { return a+b; }
3、无法通过重载来改变运算符的优先级。
4、不能改变操作数的个数。
5、不能发明新的运算符。
注意:运算符的重载要注重一致性(与默认的运算规则一致)、可读性(运算符的重载是为提高代码的可读性、便捷性、要有意义,而不是自找麻烦)。