运算符重载 Operator Overload
可以为运算符增加一些新的功能
class Point {
private:
int m_x;
int m_y;
public:
Point(int x, int y) :m_x(x), m_y(y) {}
void display() {
cout << "(" << m_x << ", " << m_y << ")" << endl;
}
};
-
直接将两个
Point
类相加得到新的点比如
Point p3 = p1 + p2;
,这样就要使用运算符重载,因为平常加号两端不可以是Point
类的
class Point {
friend Point operator+(const Point &, const Point &);
private:
int m_x;
int m_y;
public:
Point(int x, int y) :m_x(x), m_y(y) {}
void display() {
cout << "(" << m_x << ", " << m_y << ")" << endl;
}
};
Point operator+(const Point &p1, const Point &p2) {
return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
// 1. 传入的Point类最好加上引用,避免产生不必要的中间变量
// 2. 最好加上const,这样const和非const对象都可以传入,接受范围大一些
// 3. 加上const和引用后,友元函数传入参数也要加const和引用
int main() {
Point p1(10, 20);
Point p2(20, 30);
Point p3 = p1 + p2;
// 相当于 Point p3 = operator+(p1, p2);
}
为运算符加号’+'增加新的功能,返回一个point。
这样是把运算符重载函数放在类外面,如果放到里面变成一个成员函数,就只要传入一个Point对象就可以了,并且也不需要声明友元函数了。
class Point {
private:
int m_x;
int m_y;
public:
Point(int x, int y) :m_x(x), m_y(y) {}
void display() {
cout << "(" << m_x << ", " << m_y << ")" << endl;
}
// 最左边的const为了防止返回的Point被赋值 (p1 + p2 = p3是不允许的)
// 最右边的const为了const返回值又可以调用operator+ (但要允许p1 + p2 + p3)
const Point operator+(const Point &point) const{
return Point(this->m_x + point.m_x, this->m_y + point.m_y);
// 或者省略this
// return Point(m_x + point.m_x, m_y + point.m_y);
}
};
int main() {
Point p1(10, 20);
Point p2(20, 30);
p1 + p2;
// 相当于 p1.operator+(p2);
}
所以,全局函数、成员函数都支持运算符重载
返回值最好是个const对象,返回值不允许再被赋值,但加上const之后就不允许连续相加了。所以要再加一个const。
- 再实现一下+=
class Point {
private:
int m_x;
int m_y;
public:
Point(int x, int y) :m_x(x), m_y(y) {}
void display() {
cout << "(" << m_x << ", " << m_y << ")" << endl;
}
// 最左边的const为了防止返回的Point被赋值
// 最右边的const为了const返回值又可以调用operator+
const Point operator+(const Point &point) const{
return Point(this->m_x + point.m_x, this->m_y + point.m_y);
// 或者省略this
// return Point(m_x + point.m_x, m_y + point.m_y);
}
// 为了能够再赋值,返回是当前对象而不是地址,所以返回*this而不是this,返回this就是返回当前对象的地址
// 加引用是为了防止产生中间变量,如果将类里面返回的函数拿到另一个函数中用,会重新拷贝构造出一个新的对象
Point &operator+=(const Point &point) {
m_x += point.m_x;
m_y += point.m_y;
return *this;
}
};
int main() {
Point p1(10, 20);
Point p2(20, 30);
p1 += p2;
// 相当于 p1.operator+=(p2);
(p1 += p2) = Point(50, 60);
// p1 = p1 + p2;
// p1 = Point(50, 60);
}
- 完成
-p1
的操作(单目运算符)
const Point operator-() const {
return Point(-m_x, -m_y);
}
- 前置++和后置++
// 前置++, ++p
Point &operator++() {
m_x++;
m_y++;
return *this;
}
// 后置++(加一个int,只能是int,无论内部是什么样),p++
const Point operator++(int) {
Point old(m_x, m_y);
m_x++;
m_y++;
return old;
}
-
注意:
-
前置++可以被赋值,后置++不可以
比如:
++a = 20; // 可以 (a++) = 20; // 不可以
所以前置++返回是一个对象的引用
后置++返回的是
const Point
-
-
左移,实现
cout << p1 << endl;
// 不能写 void operator<<() // 因为<<不是单目运算符 // 下面这个写法相当于 // p1 << 10; // p1.operator<<(10) void operator<<(int a) { } // 但我们要实现的是cout << p1 << endl; 传入point // 它就不能是成员函数,必须是全局函数,所以要将其加入Point的友元函数 // cout也是对象,是ostream对象(output stream) // 如果要实现cout << p1 << p2; // 就要返回cout,这很重要! // 但cout的返回值是不能再被赋值的,可以把这个函数放到private中,这样就不会再被赋值 ostream &operator<<(ostream &cout, const Point& point) { cout << "(" << point.m_x << ", " << point.m_y << ")"; return cout; }
-
右移,实现输入
// input stream -> istream istream &operator>>(istream &cin, Point &point) { cin >> point.m_x; cin >> point.m_y; return cin; }
-
调用父类的运算符重载函数
-
运算符重载注意点
-
有些运算符不可以被重载
- 对象成员访问运算符:
.
- 域运算符:
::
- 三目运算符:
?:
sizeof
- 对象成员访问运算符:
-
有些运算符只能写在类里面重载为成员函数,比如
- 赋值运算符:
=
- 下标运算符:
[]
- 函数运算符:
()
- 指针访问运算符:
->
- 赋值运算符:
-