- 重载算数操作符
- 重载操作符[]
- 重载关系操作符
- 重载类型转换操作符
- 重载输入输出操作符
引例
用一个类Fraction
,用于表示2/3
, 87/890
这种分数
class Fraction
{
public:
Fraction(int n ,int d): num(n), den(d)
{
}
int num; // 分子
int den; // 分母
};
// 定义两个数
Fraction fa(2,3); // 2/3
Fraction fb(3,5); // 3/5
按理来说,两个数是可以进行算术运算的 例如:
int a = 2;
int b = 3;
int c = a + b;
对于我们自定义的Fraction
这种类型,默认情况下是不支持算术运算的,我们希望它也能够支持加减乘除
的算术运算
// 希望可以达到这种效果
Fraction fc = fa + fb;
一、重载算术运算符
使用重载运算符
的语法,可以使得自己定义的类支持加减乘除等算术运算符
- 第一种方式: 类操作符
// 重载加号操作符
Fraction operator + (const Fraction& other)
{
Fraction result;
// 本对象和other运算,得出结果并返回
return result;
}
// 在 fc = fa + fb 语句中,operator+被调用
注意:
(1)重载操作符的形式上像一个函数,但它不是函数
(2)名称:operator +
,这个是固定不变的
(3)返回值:类型不变,总是为该对象的类型
(4)参数:基本上也不变
(5)受public/protected/private
的限制
- 另一种写法:重载全局操作符
// 重载全局操作符
Fraction operator + (const Fraction& a, const Fraction& b)
{
Fraction result;
result.den = a.den * b.den;
result.num = a.num * b.den + a.den * b.num; return result;
}
通常,要将全局操作符的重载声明为类的朋友
当num/den为private
的时候,必须将此重载的操作符声明为friend
注意
(1)当类操作符和全局操作符同时被重载时,类操作符被优先调用 (就近原则)
(2)各种重载操作符,其形式基本是固定的。(名称、参数、返回值,基本上都是固定写法)给出加号(+)的示例。其他的操作符(-, * , / ) 也是一样的
(3)通常,要将全局操作符的重载声明为类的朋友
举例
实现两个Point相加,即
Point p1(10,20);
Point p2(20,30);
Point p = p1 + p2;
代码如下:
class Point{
friend Point operator+ (const Point &, const Point &);
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(const Point &point) {
m_x = point.m_x;
m_y = point.m_y;
}
}
// 重载全局操作符
Point operator+(const Point &p1, const Point &p2) {
return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
既然我们是实现Point的运算符重载,所以最好还是将运算符重载的操作放在Point类内部,不用写成全局函数的好
二、重载操作符[]
[]
用于访问一组元素中的一个元素,默认地,数组是支持下标访问的。
int a[5] = {1,2,3,4,5};
a[0] = 111; // 写操作
int b = a[0]; // 读操作
[]
中的下标称为:索引,其作用是用来唯一的标识一个元素
什么时候要重载 [ ]
当一个对象设计用于包含多个元素
时,可以重载操作符[]
比如:一个字符串Text,它包含了多个元素(每个元素是一个字符)
Text txt("hello world");
char ch = txt[0]; // 'h'
比如:在一个DataStore里存储多个Student数据
DataStore ds;
Student& st = ds["shaofa"]; // 查找姓名为"shaofa"的记录
重载操作符的一般形式
Element& operator [] (Type index)
{
}
其中:
名字: operator[]
,是固定不变的
返回值:一般应该返回一个子元素的引用,表示返回值是一个“左值”,可读可写
参数:类型可以自己选择,用于指定元素的下标。不一定非要使用int
,使用其他类型也可以。
示例
Text类用于存储一串文本
char& operator[] (int index)
{
return m_buf[index];
}
注意
(1) 操作符[]的返回值类型为引用
,才算是符合使用惯例。
(即:应该返回一个左值
)
(2) 元素下标的类型是不一定要用int
,用char*
也可以
(3) 操作符[]
是可以重载的,参数类型不同
(4) 必须考虑元素不存在的情形
三、重载关系操作符
关系操作符: <, <=, >, >=, ==, !=
默认地,编译器不支持对自定义的类进行关系操作。例如,我们想判断两个分数Fraction是否相等
Fraction fa(2, 3);
Fraction fb(4, 6);
if(fa == fb) // 编译器报错!不支持==
{
}
操作符==的重载方法
(1) 重载类操作符
class Object
{
public:
bool operator == (const Object& other){ }
};
(2) 重载全局操作符
bool operator == (const Object& a, const Object& b )
{}
代码框架:
class Fraction
{
public:
///////////////////////////////
bool operator == (const Fraction& other)
{
return true;
}
};
四、类型转换操作符
C++中允许将一个类型转换为另一个类型
int a = (int) 1.23; // 将double转成int
比如,现在自己定义了一个类Fraction,表示分数。
那么怎么样才可以把Fraction类型直接转成一个double类型呢?
重载类型转换操作符 ()
class Object
{
public:
operator Type() // Type为目标类型
{
Type result;
return result;
}
};
五、输入输出操作符
C++中引入操作符 >> 表示输入, <<表示输出
(注意:位操作里它们承担的意思是:左移位、右移位,这里不要混淆了)
// 在位操作中:
unsigned int a = 0xAA << 4;
(左操作数为整型时,表示移位)
Logger lg;
lg << "hello,world";
(左操作数为自定义对象,表示输入输出)
演示输出操作符 << 的用法
// 定义一个类: Logger,用于输出打印日志
Logger& operator << (Type value)
{
return *this;
}
// 定义一个对象
Logger lg;
lg << 1;
lg << 2.0;
lg << "hello";
// 或者串起来写
lg << 1 << ", " << 2.0 << "hello" ;
名称: operator <<
返回值:左值,一般返回对象自己
参数:待输出的数据
说明
-
注意:为什么返回左值?
因为,如果不返回左值,就没法串起来写。 -
C++是借用了这两个操作符
当左操作数为整数时,表示“移位”
当为自定义类型class时,表示“输入、输出”
网友评论