运算符重载-总结
我们现在在一篇笔记中总结一下。
运算符重载是一个建立在类与对象上的关键点。如果没学习到/复习到,建议先把类与对象学习/复习完成后在进行。
在这一篇笔记之中,主要是对知识点、语法的总结。四则运算等部分重载只会写一个用于参考。所以每个实例都回把所使用到的类也写出来。
概念
- 运算符重载在 c++中是一个非常重要的知识点。
- 概念:对已有的运算符进行重新定义,赋予它另外的一种功能,用来适应不同的数据类型。
- c++中实现运算符重载需要使用关键字:
operator
。
注意
- 内置的数据类型的表达式运算不可以修改。
- 运算符的重载的本质是函数调用。
- 运算符重载可以出现函数重载
- 因为运算符重载的本质就是函数。
- 不要滥用运算符重载。
- 如果重载的是加法(
+
),但是在重载的函数里面实现了一堆奇奇怪怪的内容。
- 如果重载的是加法(
- 运算符重载必须使用引用的方法传入。
- 不可以使用使用指针的方式传入,虽然引用本质上是一个指针常量(可以修改数据/指针不可以被修改)。
- 部分重载需要使用特定的重载方式(比如强制在成员函数或者全局函数中)。
- 也可以在类中声明重载函数,然后在类外定义函数(只要把作用域添加上就可以了)。
概览
重载内容 | 是否可以成员函数重载 | 是否可以全局函数重载 | 语法 | 返回值类型 |
---|---|---|---|---|
四则运算 | Y | Y | class test operator+(class test& p) /class test operator+(class test& p1, class test& p2); |
类本身 |
输入输出-左移 | N | Y | ostream& operator<<(ostream& cout, class test& p); |
ostream& |
输入输出-右移 | N | Y | istream& operator>>(istream& cin, class test& p) |
istream& |
递增递减 | Y | Y* | class test& operator++() /class test operator++(int) /class test& operator++(class test& p); |
类本身或者引用的类本身 |
赋值 | Y | N | class test& operator=(class test& p) |
类本身 |
关系运算符 | Y | Y | bool operator==(class test& p) /bool operator==(class test& p1, class test& p2); |
布尔bool |
仿函数 | Y | N | void operator()(形式参数列表) |
void ,因为可以当函数用所以看实际需求返回。 |
逻辑运算符 | Y | Y | bool operator&&(class test& p1, class test& p2) |
布尔bool |
*:递增递减中,前置可以在全局函数中重载,但是后置不可以。
示例
-
四则运算重载
-
实现方式:
- 在成员函数里面实现重载。
- 在全局函数里面实现重载。
-
示例:
-
在成员函数里面实现重载。
class test { public: int m_A; int m_B; class test operator+(class test& p) { class test temp; temp.m_A = this->m_A + p.m_A; temp.m_B = this->m_B + p.m_B; return temp; } };
-
在全局函数里面实现重载。
class test operator+(class test& p1, class test& p2); class test { public: int m_A; int m_B; }; class test operator+(class test& p1, class test& p2) { class test temp; temp.m_A = p1.m_A + p2.m_A; temp.m_B = p1.m_B + p2.m_B; return temp; }
-
-
注意事项:
- 四则运算的运算符重载可以重载的运算:
- 加法(
+
) - 减法(
-
) - 乘法(
*
) - 除法(
/
) - 取模运算(
%
)
- 加法(
- 四则运算的运算符重载可以重载的运算:
-
-
输入输出-左移运算符重载
-
实现方式:
- 在全局函数里面实现重载。
-
示例:
-
在全局函数里面实现重载。
ostream& operator<<(ostream& cout, class test& p); class test { public: int m_A; int m_B; }; ostream& operator<<(ostream& cout, class test& p) { cout << "m_A = " << p.m_A << " m_B = " << p.m_B; return cout; }
-
-
注意事项:
- 为了能够实现链式编程,所以返回值也是引用的方式返回。
- 左移运算符只可以在全局函数重载。
cout
是标准输出流(ostream
)下的功能。
-
-
输入输出-右移运算符重载
-
实现方式:
- 在全局函数里面实现重载。
-
示例:
-
在全局函数里面实现重载。
istream& operator>>(istream& cin, class test& p); class test { public: int m_A; int m_B; }; istream& operator>>(istream& cin, class test& p) { cin >> p.m_A >> p.m_B; return cin; }
-
-
注意事项:
- 为了能够实现链式编程,所以返回值也是引用的方式返回。
- 右移运算符只可以在全局函数重载。
cin
是标准输入流(istream
)下的功能。
-
-
递增递减重载
-
实现方式:
- 在成员函数里面实现重载。
- 在全局函数里面实现重载(仅限前置)。
-
示例:
-
在成员函数里面实现重载。
- 前置递增
class test { public: int m_A; int m_B; class test& operator++() { m_A++; m_B++; return *this; } };
- 后置递增
class test { public: int m_A; int m_B; class test operator++(int) { class test temp = *this; m_A++; m_B++; return temp; } };
-
在全局函数里面实现重载(仅限前置)。
class test& operator++(class test& p); class test { public: int m_A; int m_B; }; class test& operator++(class test& p) { p.m_A++; p.m_B++; return p; }
-
-
注意事项:
- 为了实现多次前置递增,所以前置递增需要使用引用的方式返回。
- 连续多次非自定义类型的数值后置递增是会报错的,并且存放在堆区的数据在函数运行完成后自动释放,所以后置递增不使用引用方式返回。
- 只有前置递增才可以在全局函数中重载。
- 后置递增的重载需要在函数的形式参数列表中加上
int
,这是一个占位参数。
-
-
赋值重载
-
实现方式:
- 在成员函数里面实现重载。
-
示例:
-
在成员函数里面实现重载。
class test { public: int* p_m_A; int m_B; ~test() { if (p_m_A != NULL) { delete p_m_A; p_m_A = NULL; } } class test& operator=(class test& p) { if (p_m_A != NULL) { delete p_m_A; p_m_A = NULL; } p_m_A = new int(*p.p_m_A); m_B = p.m_B; return *this; } };
-
-
注意事项:
- 赋值重载主要出现在类中存在指向栈区的地址时使用。
- 如果类中出现栈区地址,务必提供析构函数,释放占用的栈区内存。
- 使用赋值重载的时候,如果类中存在指向栈区的地址,请先释放被赋值的对象中占用的栈区内存。
- 如果类中没有指向堆区的地址,可以使用编译器提供的默认赋值。(默认提供值拷贝)。
-
-
关系运算符
-
实现方式:
- 在成员函数里面实现重载。
- 在全局函数里面实现重载。
-
示例:
-
在成员函数里面实现重载。
class test { public: int m_A; int m_B; test() { m_A = 10; m_B = 20; } bool operator==(class test& p) { if (m_A == p.m_A && m_B == p.m_B) { return true; } else { return false; } } };
-
在全局函数里面实现重载。
bool operator==(class test& p1, class test& p2); class test { public: int m_A; int m_B; }; bool operator==(class test& p1, class test& p2) { if (p1.m_A == p2.m_A && p1.m_B == p2.m_B) { return true; } else { return false; } }
-
-
注意事项:
- 关系运算符返回的是布尔值(
bool
),可以返回true
或者false
。当然也可以用数字代替。1
表示true
,0
表示false
。 - 在 c++中,
&&
表示逻辑与,也可以用and
代替;||
表示逻辑或,也可以用or
代替。 - 关系运算符重载可以重载的运算:
- 等于(
==
) - 不等于(
!=
) - 大于(
>
) - 小于(
<
) - 大于或等于(
>=
) - 小于或等于(
<=
)
- 等于(
- 关系运算符返回的是布尔值(
-
-
函数调用(小括号)重载(仿函数)
-
实现方式:
- 在成员函数里面实现重载。
-
示例:
-
在成员函数里面实现重载。
class test { public: int operator()(int a) { cout << "a= " << a << endl; return 0; } };
-
-
注意事项:
- 可以生成形如:
test()(100)
匿名函数对象调用函数重载。 - 仿函数基本可以当做函数使用。
- 在STL内容中大量使用。
- 可以生成形如:
-
-
逻辑运算符
-
实现方式:
- 在成员函数里面实现重载。
- 在全局函数里面实现重载。
-
示例:
-
在成员函数里面实现重载。
class test { public: int m_A; int m_B; bool operator&&(class test& p) { if ((m_A == p.m_A) && (m_B == p.m_B)) { return true; } else { return false; } } };
-
在全局函数里面实现重载。
bool operator&&(class test& p1, class test& p2); class test { public: int m_A; int m_B; }; bool operator&&(class test& p1, class test& p2) { if ((p1.m_A == p2.m_A) && (p1.m_B == p2.m_B)) { return true; } else { return false; } }
-
-
注意事项:
-
尽量不要使用逻辑运算符重载,因为会改变逻辑运算符的原本性质。
-
操作符重载本质是函数重载,函数的参数都会进行求值运算,改变了原来逻辑运算符的特性。
-
逻辑运算符可以重载的内容:
- 逻辑与(
&&
/and
) - 逻辑或(
||
/or
)
- 逻辑与(
-
-
:-)