目录七
二十.操作符重载(operator)
2.双目操作符重载: L#R(L:左操作数;R:右操作数)
2.1 运算类的双目操作符:+ -
①表达式结果是右值,不能对表达式结果再赋值(加const,不能加引用&)
②左右操作数既可以是左值也可以是右值
③具体实现方式有两种:
1)成员函数形式(左调右参:左操作数c1作为调用对象,右操作数c2是参数对象)
a. 成员函数定义在类里面。
b. L#R的表达式可以被编译器处理为L.operator#(R)的成员函数调用形式,由该函数实现自定义的运算功能,其返回结果就是表达式的结果。
eg.
//重载+:成员函数形式
//c1+c2 ==> c1.operator+(c2)
2)全局函数形式(左右操作数c1,c2都是参数)
a. 假如全局函数定义在类外,若想访问到类中的成员变量,需要在类中用friend关键字声明下全局函数。也可以把友元函数直接定义在类的内部,但是其本质还是属于全局函数,并不属于类。
b. L#R的表达式也可以被编译器处理为operator#(L,R)的全局函数调用形式,由该函数实现自定义的运算功能,其返回结果就是表达式的结果
(注:可以使用friend关键字,将全局函数形式操作符重载函数,声明为类的友元,友元函数可以访问类中任何成员。)
eg.
//重载-:全局函数形式
//c2-c1 ==> operator-(c2,c1)
eg.
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r,int i):m_r(r),m_i(i){}
void print(void) const {
cout << m_r << "+" << m_i << 'i' << endl;
}
//重载+:成员函数形式
//c1+c2 ==> c1.operator+(c2)
//1)第一个const:修饰返回值,禁止对表达式结果再赋值
//2)第二个const:常引用,支持常量型右操作数
//3)第三个const:常成员函数,支持常量型左操作数
const Complex operator+(
const Complex& c) const {
Complex res(m_r+c.m_r,m_i+c.m_i);
return res;
}
private:
int m_r;//实部
int m_i;//虚部
//友元
friend const Complex operator-(
const Complex& left,const Complex& right);
};
//重载-:全局函数形式
//c2-c1 ==> operator-(c2,c1)
const Complex operator-(
const Complex& left,const Complex& right){
Complex res(left.m_r-right.m_r,
left.m_i-right.m_i);
return res;
}
int main(void){
const Complex c1(1,2);
const Complex c2(3,4);
c1.print();
c2.print();
//Complex c3 = c1.operator+(c2)
Complex c3 = c1 + c2;
c3.print();//4+6i
Complex c4 = c2 - c1;
c4.print();//2+2i
return 0;
}
2.1 赋值类的双目操作符:+= -=
①表达式结果是左值,就是左操作数的自身(不加const,加引用&)
②左操作数必须是左值,右操作数左值或右值都可以
③具体实现方式有两种:
1)成员函数形式
L#R ==> L.operator#(R)
2)全局函数形式
L#R ==> operator#(L,R)
eg.
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r,int i):m_r(r),m_i(i){}
void print(void) const {
cout << m_r << "+" << m_i << 'i' << endl;
}
//+=:成员函数形式
//c1+=c2 ==> c1.operator+=(c2)
Complex& operator+=(const Complex& c){
m_r += c.m_r;
m_i += c.m_i;
return *this; // 返回自身
}
//-=:全局函数形式
//c1-=c2 ==> operator-=(c1,c2)
//可以把友元函数直接定义在类的内部,但是其本质还是属于全局函数,并不属于类.
friend Complex& operator-=(
Complex& left,const Complex& right){
left.m_r -= right.m_r;
left.m_i -= right.m_i;
return left; //返回左操作数的自身
}
private:
int m_r;//实部
int m_i;//虚部
};
int main(void){
Complex c1(1,2);
Complex c2(3,4);
c1 += c2;
c1.print();//4+6i
Complex c3(5,6);
(c1 += c2) = c3;
c1.print();//5+6i
c1 -= c2;
c1.print();//2+2i
(c1 -= c2) = c3;
c1.print();//5+6i
return 0;
}
3.单目操作符重载:#O
3.1 运算类单目操作符:-(负) ~
①表示结果(-a )是右值,不能对表达式结果再赋值(加const,不能加引用&)
②操作数可以是左值也可以是右值
③具体实现方式有两种:
1)成员函数形式
#O ==> O.operator#()
2)全局函数形式
#O ==> operator#(O)
eg.
#include <iostream>
using namespace std;
class Integer{
public:
Integer(int i=0):m_i(i){}
void print(void) const {
cout << m_i << endl;
}
//-(负):成员函数形式
const Integer operator-(void) const {
Integer res(-m_i);
return res;
}
//~:全局函数形式(自定义表示平方)
friend const Integer operator~(
const Integer& i){
Integer res(i.m_i * i.m_i);
return res;
}
private:
int m_i;
};
int main(void){
Integer i(100);
Integer j = -i;//i.operator-();
j.print();//-100
j = ~i;//operator~(i);
j.print();//10000
return 0;
}
3.2 自增减单目操作符:++ - -
3.2.1 前缀自增减
①表达式结果是左值,就是操作数自身
②操作数一定是左值
③两种实现方式:
成员函数形式:#O ==> O.operator#()
全局函数形式:#O ==> operator#(O)
eg.
//前++:成员函数形式
//++i ==> i.operator++();
Integer& operator++(void){
++m_i;
return *this;
}
//前--:全局函数形式
//--i ==> operator--(i);
friend Integer& operator--(Integer& i){
--i.m_i;
return i;
}
3.2.2 后缀自增减
①表达式结果是右值,是操作数自增减之前的数值
②操作数一定是左值
③两种实现方式:
成员函数形式:O# ==> O.operator#(int/*哑元*/)
全局函数形式:O# ==> operator#(O,int/*哑元*/)
eg.
//后++:成员函数形式
//i++ ==> i.operator++(0/*哑元*/)
const Integer operator++(int/*哑元*/){
Integer old = *this;
++(*this);//++m_i;
return old;
}
//后--:全局函数形式
//i-- ==> operator--(i,0/哑元/)
friend const Integer operator--(Integer& i,int/*哑元*/){
Integer old = i;
--i;//--i.m_i;
return old;
}
eg.
#include <iostream>
using namespace std;
class Integer{
public:
Integer(int i=0):m_i(i){}
void print(void) const {
cout << m_i << endl;
}
//前++:成员函数形式
//++i ==> i.operator++();
Integer& operator++(void){
++m_i;
return *this;
}
//前--:全局函数形式
//--i ==> operator--(i);
friend Integer& operator--(Integer& i){
--i.m_i;
return i;
}
//后++:成员函数形式
//i++ ==> i.operator++(0/*哑元*/)
const Integer operator++(int/*哑元*/){
Integer old = *this;
++(*this);//++m_i;
return old;//返回自增加之前的数值
}
//后--:全局函数形式
//i-- ==> operator--(i,0/哑元/)
friend const Integer operator--(Integer& i,int/*哑元*/){
Integer old = i;
--i;//--i.m_i;
return old;//返回自增减之前的数值
}
private:
int m_i;
};
int main(void){
Integer i(100);
Integer j = ++i;
i.print();//101
j.print();//101
j = ++++i;
i.print();//103
j.print();//103
j = --i;
i.print();//102
j.print();//102
j = ----i;
i.print();//100
j.print();//100
j = i++;
i.print();//101
j.print();//j保存的是i++的表达式结果,所以是100
j = i--;
i.print();//100
j.print();//同理j保存的是表达式结果,为101
return 0;
}
4.输出(插入)和输入(提取)操作符重载:<< >>
功能:实现自定义类型对象的直接输出或输入
(注:ostream和istream是标准库的类,不能直接修改,所以重载时只能选择全局函数形式)
#include <iostream>
ostream//标准输出流类,cout是ostream类型的对象
istream//标准输入流类,cin是istream类型的对象
//输出操作符重载函数
friend ostream& operator<<(ostream& os,const Right& r){
...
return os;
}
//输入操作符重载函数
friend istream& operator>>(istream& is,Right& r){
...
return is;
}
(PS:以后用上面这段代码时,直接往里面套,把Right换成类名就行,注意输出中有const,输入中没有const)
//全局函数:operator<<(cout,a)
cout << a << ...;
//全局函数:operator>>(cin,a)
cin >> c >>...;
eg.
#include <iostream>
using namespace std;
class Complex{
public:
Complex(int r,int i):m_r(r),m_i(i){}
//重载输出<<
friend ostream& operator<<(
ostream& os,const Complex& c){
os << c.m_r << '+' << c.m_i << 'i';
return os;
}
//重载输入>>
friend istream& operator>>(
istream& is,Complex& c){
cout << "请输入实部:";
is >> c.m_r;
cout << "请输入虚部:";
is >> c.m_i;
return is;
}
private:
int m_r;//实部
int m_i;//虚部
};
int main(void){
Complex c1(1,2);
Complex c2(3,4);
//operator<<(cout,c1)
cout << c1 << endl;
cout << c1 << ',' << c2 << endl;
Complex c3(0,0);
//operator>>(cin,c3)
cin >> c3;
cout << "c3:" << c3 << endl;
return 0;
}
练习
练习:实现一个3*3矩阵类,支持如下操作符重载
+ - += -= -(负) 前后++、-- <<
* *=
提示:
class M33{
public:
private:
int m_a[3][3];
};
1 2 3 9 8 7 10 10 10
4 5 6 + 6 5 4 = 10 10 10
7 8 9 3 2 1 10 10 10
---------------------------
1 2 3 9 8 7 -8 -6 -4
4 5 6 - 6 5 4 = -2 0 2
7 8 9 3 2 1 4 6 8
----------------------------
1 2 3 9 8 7 30 24 18
4 5 6 * 6 5 4 = 84 69 54
7 8 9 3 2 1 138 114 90
eg.
#include <iostream>
using namespace std;
class M33
{
public:
//初始化数组为0,无参构造
//M33(void)
//{
// for (int i = 0; i < 3; i++)
// {
// for (int j = 0; j < 3; j++)
// {
// aa[i][j] = 0;
// }
// }
//}
//有参构造
M33(int a[][3])
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
aa[i][j] = a[i][j];
}
}
}
//输出操作符重载: <<
//用来显示3*3矩阵
friend ostream& operator<<(ostream& os, const M33& arr)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
os << arr.aa[i][j] << " ";
}
os << endl;
}
return os;
}
//重载+:成员函数形式
//c1+c2 ==> c1.operator+(c2)
//1)第一个const:修饰返回值,禁止对表达式结果再赋值
//2)第二个const:常引用,支持常量型右操作数
//3)第三个const:常成员函数,支持常量型左操作数
const M33 operator+(const M33& c) const
{
int a[3][3] = { 0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
a[i][j] = aa[i][j] + c.aa[i][j];
}
}
M33 add(a);
return add;
}
//重载-:成员函数形式
const M33 operator-(const M33& c) const
{
int a[3][3] = { 0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
a[i][j] = aa[i][j] - c.aa[i][j];
}
}
M33 sub(a);
return sub;
}
//+=:成员函数形式
//c1+=c2 ==> c1.operator+=(c2)
M33& operator+=(const M33& c)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
aa[i][j] += c.aa[i][j];
}
}
return *this; // 返回自身
}
//-=:成员函数形式
//c1-=c2 ==> operator-=(c1,c2)
M33& operator-=(const M33& c)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
aa[i][j] -= c.aa[i][j];
}
}
return *this; // 返回自身
}
//-(负):成员函数形式
const M33 operator-(void) const
{
int a[3][3] = { 0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
a[i][j] = 0 - aa[i][j];
}
}
M33 neg(a);
return neg;
}
//前++:成员函数形式
//++i ==> i.operator++();
M33& operator++(void)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
++aa[i][j];
}
}
return *this;
}
//前--:全局函数形式
//--i ==> operator--(i);
M33& operator--(void)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
--aa[i][j];
}
}
return *this;
}
//后++:成员函数形式
//i++ ==> i.operator++(0/*哑元*/)
const M33 operator++(int/*哑元*/)
{
M33 old = *this;
++(*this);//++m_i;
return old;
}
//后--:全局函数形式
//i-- ==> operator--(i,0/哑元/)
friend const M33 operator--(M33& i, int/*哑元*/)
{
M33 old = i;
--i;//--i.m_i;
return old;
}
private:
int aa[3][3];
};
int main(void)
{
int a[3][3] = { 1,2,3,4,5,6,7,8,9 };
int b[3][3] = { 9,8,7,6,5,4,3,2,1 };
M33 a1(a);
M33 a2(b);
cout << a1 << endl;
cout << a2 << endl;
cout << "a1+a2:" << endl;
cout << a1+a2 << endl;
cout << "a1-a2:" << endl;
cout << a1 - a2 << endl;
cout << "a1+=a2:" << endl;
cout << (a1 += a2) << endl;
cout << "a1:" << endl;
cout << a1 << endl;
cout << "a1-=a2:" << endl;
cout << (a1 -= a2) << endl;
cout << "a1:" << endl;
cout << a1 << endl;
cout << "-a2:" << endl;
cout << -a2 << endl;
cout << "++a2:" << endl;
cout << ++a2 << endl;
cout << a2 << endl;
cout << "--a2:" << endl;
cout << --a2 << endl;
cout << a2 << endl;
cout << "a2++:" << endl;
cout << a2++ << endl;
cout << a2 << endl;
cout << "a2--:" << endl;
cout << a2-- << endl;
cout << a2 << endl;
return 0;
}
5.下标操作符重载:[]
功能:实现自定义类型对象能够像数组一样使用
(注:非const对象返回左值,常对象返回右值)
string str = "..."
//str.operator[](i) == 'A'
str[i] = 'A';
eg.string str = "zhangsan";
str.operator[](0) = 'Z';
str[0] = 'Z'; //和上面等价
--------------------
const string str = "..."
//str.operator[](i) == 'A'
str[i] = 'A';//error
eg.
#include <iostream>
using namespace std;
//模拟容器类:里面可以存放若干个int数据
class Array{
public:
Array(size_t size){
m_arr = new int[size];
}
~Array(void){
delete[] m_arr;
}
//下标操作符重载:[]
int& operator[](size_t i){
cout << "匹配非const对象" << endl;
return m_arr[i];
}
const int& operator[](size_t i)const{
cout << "匹配const对象" << endl;
return m_arr[i];
}
private:
int* m_arr;
};
int main(void){
Array arr(10);
arr[0] = 123;//arr.operator[](0) = 123
cout << arr[0] << endl;//123
const Array& arr2 = arr; //常引用
//arr2[0] = 321;//应该error
cout << arr2[0] << endl;//123
return 0;
}
6.函数操作符: ()
功能:实现让自定义类型的对象像函数一样去使用//仿函数
(注:对参数个数、类型和返回值没有任何限制)
A a(...);
a(100,1.23);//a.operator()(100,1.23)
eg.
#include <iostream>
using namespace std;
class Func{
public:
int operator()(int i,int j){
return i * j;
}
int operator()(int i){
return i * i;
}
};
int main(void){
Func func;//仿函数
//func.operator()(100,200)
cout << func(100,200) << endl;//20000
//func.operator()(100)
cout << func(100) << endl;//10000
return 0;
}
7.new和delete操作符重载(了解)
static void* operator new(size_t size){...}
static void operator delete(void* p){...}
eg.
#include <iostream>
#include <cstdlib>
using namespace std;
class A{
public:
A(void){
cout << "A的构造函数" << endl;
}
~A(void){
cout << "A的析构函数" << endl;
}
static void* operator new(size_t size){
cout << "分配内存" << endl;
void* pv = malloc(size);
return pv;
}
static void operator delete(void* pv){
cout << "释放内存" << endl;
free(pv);
}
};
int main(void){
//1)A* pa = (A*)A::operator new(sizeof(A))
//2)pa->构造函数
A* pa = new A;
//1)pa->析构函数
//2)A::operator delete(pa)
delete pa;
pa = NULL;
return 0;
}
8.操作符重载限制
①不是所有操作符都能重载,下面操作符不能重载:
---》作用域限定操作符 "::"
---》直接成员访问操作符 "."
---》直接成员指针解引用操作符 ".*"
---》条件操作符 "?:"
---》字节长度操作符 "sizeof"
---》类型信息操作符 "typeid"//后面讲
②如果一个操作符所有的操作数都是基本类型,则无法重载
③操作符重载不会改变编译器预定义的优先级
④操作符重载不会改变操作数个数
⑤无法通过操作符重载发明新的符号
⑥只能使用成员函数形式重载操作符
= [] () ->