运算符重载 运算符重载是多态的一种形式。指c++允许赋予同一运算符多种含义。
运算符重载可使自定义类型(类等)看起来更像基本的数据类型。
使用 operator
声明重载函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #pragma once class Point {private : double m_x; double m_y; protected :public : Point (); Point (double x, double y); ~Point (); void set_x (int x) { m_x = x; } double get_x () const { return m_x; } void set_y (int y) { m_y = y; } double get_y () const { return m_y; } Point operator +(const Point& b) const { Point r (m_x + b.m_x, m_y + b.m_y) ; return r; } }; int main () { Point x (1 , 2 ) , y (3 , 4 ) ; Point z = x + y; cout << z.get_x () << " " << z.get_y () << endl; return 0 ; }
调用 z = x + y;
相当于 z = x.operator+(y);
重载限制 重载后的运算符必须至少一个操作数是用户自定义类型。
使用运算符重载不能违反运算符原来的句法规则,如操作数的个数和优先级等。
不能创建新运算符。
有些运算符不能重载。
有些运算符只能通过成员函数重载,而不能通过非成员函数重载,如下。
非同类型重载 1 2 3 4 5 6 Point operator *(double v) const { Point r (m_x*v, m_y*v) ; return r; } Point x (1 , 2 ) ;Point z = x*2.0 ;
友元函数 上面的语句z = x*2.0;
会转换成z = x.operator*(2.0);
,但是若语句为z = 2.0*x;
呢,就无法达到与上式一样的效果。
一个解决办法是使用非成员函数。
1 Point operator *(double a, const Point& b);
那么将面临的问题是这个函数必须可以访问Point类
的私有成员。
可以使用友元函数
来解决这个问题。
友元函数可以访问类的私有成员,是一类特殊的非成员函数。
声明 友元函数的原型放在类中,但不是类成员函数,不用使用::
调用。
前加friend
关键字,该关键字只在声明中加,定义中不加,表示其可访问声明位置所在类的私有成员。
1 friend Point operator *(double a, const Point& b);
定义 友元函数的定义不用加friend
关键字,也不用加类名::
限定符。
这之后,z = 2.5*a;
会转化为非成员函数z = operator*(2.5, a);
。
使用 友元重载和成员函数重载只可选择一种。有时候只能用友元,如第一个参数不能是类对象时。有时候二者皆可但友元重载会更好。
有一种常用的友元函数为重载<<(重定向)
运算符。
1 friend ostream& operator <<(ostream& out, const Point& a);
改进后的Point
类如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #pragma once #include <iostream> using std::ostream;class Point {private : double m_x; double m_y; protected :public : Point (); Point (double x, double y); ~Point (); void set_x (int x) { m_x = x; } double get_x () const { return m_x; } void set_y (int y) { m_y = y; } double get_y () const { return m_y; } Point operator +(const Point& b) const ; Point operator *(double v) const ; friend Point operator *(double a, const Point& b); friend ostream& operator <<(ostream& out, const Point& a); };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include "Point.h" #include <iostream> using std::cout;using std::endl;Point::Point () { m_x = 0.0 ; m_y = 0.0 ; } Point::Point (double x, double y) { m_x = x; m_y = y; } Point::~Point () { cout << "point " << m_x << " " << m_y << "is deleted\n" ; } Point Point::operator +(const Point& b) const { Point r (m_x + b.m_x, m_y + b.m_y) ; return r; } Point Point::operator *(double v) const { Point r (m_x*v, m_y*v) ; return r; } Point operator *(double a, const Point& b){ Point r (a*b.m_x, a*b.m_y) ; return r; } ostream& operator <<(ostream& out, const Point& a) { out << a.m_x << " " << a.m_y; return out; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include "Point.h" using namespace std;int main () { Point x (1 , 2 ) , y (3 , 4 ) ; Point z = x + y; cout << z << endl; Point zz = 2.0 *x; cout << zz << endl; cout << z << endl << zz << endl; return 0 ; }
转换函数 -- 类的转换 其他类型转换到类 只含有一个参数的构造函数可以作为转换函数,进行自动(隐式)转换。
1 2 3 Point (double v) { m_x = m_y = v; } Point t = 12.0 ;
有时候并不需要上述自动转换,可在函数原型(定义中不需要)前添加explicit
关键字。
1 explicit Point (double v) ;
但是仍然可以使用显示转换。
或
当定义了Point(double);
之后,e = 12.0 + x;
即使不使用友元函数也可运行,因为12.0会隐式地转换为Point类型。
类转换到其他类型 可使用operator
关键字声明转换函数,用来将该类转换为其他类型。
1 2 operator type_name () ;operator double () ;
转换函数必须是类方法,且不能指定返回类型,不能有参数。
1 2 3 4 5 6 operator double () const ; Point::operator double () const { return m_x + m_y; } Point t; double v = t; double v = double (t);
注意不要存在二义性。
c++11之后,explicit
也可用于转换函数,以防止隐式转换。
1 2 explicit operator double () const ;double v = t;