运算符重载 |
- 运算符重载是多态的一种形式
- C++允许赋予运算符多种含义
- 运算符重载可使使用自定义类型看起来更像基本的数据类型
一个例子
- 使用
operator
声明重载函数 - 调用
z = x + y;
相当于z = x.operator+(y);
#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; }
- 使用
- 重载限制
- 重载后的运算符必须至少一个操作数是用户定义的类型
- 使用运算符重载不能违反运算符原来的句法规则 – 操作数的个数 和 优先级
- 不能创建新运算符
- 有些运算符不能重载 – 可百度一下
- 有些运算符只能通过成员函数重载 – 而不能通过非成员函数重载
= () [] ->
另一种重载 – 非同类型重载
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;
呢, 要想达到与上式一样的效果,可以使用非成员函数
Point operator*(double a, const Point& b);
- 问题是必须给Point提供可以访问私有成员的公有方法
- 使用友元函数 – 下面介绍
- 上面的语句
友元函数
- 可以访问类的私有成员
- 是一类特殊的非成员函数
声明
- 原型放在类中 – 但不是类成员函数 – 不用使用
::
前加
friend
关键字 – 声明中加, 定义中不加 – 可访问类的私有成员friend Point operator*(double a, const Point& b);
- 原型放在类中 – 但不是类成员函数 – 不用使用
- 定义
- 不用加friend关键字
- 也不用加
类名::
限定符 z = 2.5*a;
会转化为z = operator*(2.5, a);
– 非成员函数
- 选择
- 友元重载和成员函数重载只可选择一种
- 有时候只能用友元 – 第一个参数不能是类对象时
- 有时候友元重载会更好
一种常用的友元函数 – 重载<<运算符
friend ostream& operator<<(ostream& out, const Point& a);
改进后的Point类
#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); };
#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; }
#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; }
类的转换 – 转换函数 |
其他类型转换到类
只含有一个参数的构造函数可以作为转换函数,进行自动(隐式)转换
Point(double v) { m_x = m_y = v; } // Point类的一个构造函数 Point t = 12.0; // 自动转换 -- 相当于 Point obj = Point(12.0);
有时候并不需要上述自动转换 – 在函数原型(定义中不需要)前添加explicit关键字即可
explicit Point(double v);
- 但是仍然可以使用显示转换
Point t = Point(12.0);` 或 `Point t = (Point)12.0; // 旧式
- 当定义了
Point(double);
之后,z = 12.0 + x;
即使不使用友元函数也可运行
- 因为12.0会隐式地转换为Point类型
类转换到其他类型 – 转换函数
声明
operator type_name(); operator double();
- 必须是类方法
- 不能指定返回类型
- 不能有参数
使用
operator double() const; // Point的一个成员函数 Point::operator double() const { return m_x + m_y; } // 定义 Point t; double v = t; // 隐式 double v = double(t); // 显式
- 注意不要存在二义性
C++11之后, explicit 也可用于转换函数,以防止隐式转换
explicit operator double() const; double v = t; // 如果加了explicit, 则此句会报错