二十、操作符重载
1.基本概念
操作符重载就是一些具有特殊名字的函数,使用“operator#”表示,通过重载可以定义“#”符号的功能。
例如:复数“x+yi”
(1+2i)+(3+4i)=(4+6i)
2.双目操作符,+,-,*,.......
①表示的结果是右值,不能对表达式结果再赋值
②左右操作数既可以是左值,也可以是右值
③两种实现方式:
1)成员函数形式(左调右参)
形如L#R的表达式可以被编译器处理成L.operator#(R) 成员函数调用形式,该函数的返回结果就是表达式的结果
2)全局函数形式
形如L#R的表达式也可以被编译器处理成operator#(L,R)全局函数调用形式,该函数的返回结果就是表达式的结果
注:使用friend关键字将一个全局函数声明为某个类的友元,友元函数可以访问类中的任何成员
参考代码:
#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)
/*三个const的作用:
1.修饰返回值禁止对表达式赋值(返回右值)
2.常引用,支持常量型的右操作数
3.常函数,支持常量型的左操作数
*/
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& l,const Complex& r);
};
const Complex operator-(
const Complex& l,const Complex& r){
Complex res(l.m_r-r.m_r,l.m_i-r.m_i);
return res;
}
int main(void)
{
Complex c1(1,2);
Complex c2(3,4);
c1.print();
c2.print();
//Complex c3 = c1.operator+(c2)
Complex c3 = c1 + c2;
c3.print();//4+6i
return 0;
}
3.赋值类双目操作符,+=,-=,......
①表达式结果是左值
②左操作数一定是左值,右操作数可以是左值也可以是右值
③两种实现方式
1)成员函数形式
L#R ==> L.operator#(R);
2)全局函数形式
L#R ==>operator#(L,R);
参考代码:
#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& l,const Complex& r){
l.m_r -= r.m_r;
l.m_i -= r.m_i;
return l;
}
private:
int m_r;
int m_i;
};
int main(void)
{
Complex c1(1,2);
Complex c2(3,4);
c1 += c2;//c1.operator+=(c2)
c1.print();//4+6i
Complex c3(5,6);
(c1+=c2) = c3;
c1.print();//5+6i
c1 -= c2;
c1.print();//2+2i
}
4.单目操作符
1)计算类单目操作符
①表达式的结果是右值,不能对表达式结果进行赋值
②操作数既可以是左值也可以是右值
③两种实现形式
成员函数形式:#O ==> O.operator#()
全局函数形式:#O ==>operator#(O)
参考代码:
#include <iostream>
using namespace std;
class Integer{
public:
Integer(int i):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(10);
Integer j = -i;//i.operator-()
j.print();//-10
j = ~i;//operator~(i);
j.print();//100
return 0;
}
2)自增减单目操作符
前缀:
①表达式结果是左值,就是操作数的自身
②操作数必须是左值
③两种实现形式:
成员函数形式:#O ==> O.operator#();
全局函数形式:#O ==> operator#(O);
后缀:
①表达式结果是右值,是操作数自增减前的副本
②操作数必须是左值
③三种实现形式:
成员函数形式:#O ==> O.operator#(int /*哑元*/)
全局函数形式:O# ==> operator#(O,int/*哑元*/)
参考代码:
#include <iostream>
using namespace std;
class Integer{
public:
Integer(int i):m_i(i){}
void print(void)const{
cout << m_i << endl;
}
//前++:成员函数形式
Integer& operator++(void){
++m_i;
return *this;
}
//前--:全局函数形式
friend Integer& operator--(Integer& i){
--i.m_i;
return i;
}
//后++:成员函数形式
const Integer operator++(int/*哑元*/){
Integer old = *this;
++*this;//++m_i;
return old;
}
//后--:全局函数形式
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(10);
Integer j = ++i;
i.print();//11
j.print();
j = ++++i;
i.print();//13
j.print();
j = --i;
i.print();//12
j.print();
j = ----i;
i.print();//10
j.print();
j = i++;
i.print();//11
j.print();//10
//j = i++++;//error
j = i--;
i.print();//10
j.print();//11
//j = i----;//error
return 0;
}
5.输入(输出)和输入(提取)操作符:<<,>>
1)功能:实现自定义类型对象的输入和输出
注:实现自定义类型对象的输入和输出
注:只能用全局函数形式
#include <iostream>
ostream//标准输出类
istream//标准输入类
friend ostream& operator<<(
ostream& os,const Right& r){...}
friend istream& operator>>(
istream& is,Right& r){...}
参考代码:
#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){
is >> c.m_r >> 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);
cin >> c3;
cout << c3 << endl;
return 0;
}
6.下标操作符:[ ]
1)功能:可以让一个对象像数组一样去使用
注:非常对象返回左值,常对象返回右值
string s = "abc";
//s.operator[](0) = 'A'
s[0] = 'A';//ok,返回左值,
--------------------
const string s = "abc";
//s.operator[](0) = 'A'
s[0] = 'A';//error,返回右值
参考代码:
#include <iostream>
using namespace std;
//实现一个容器类,里面可以存放若干个int
class Array{
public:
Array(size_t size){
m_arr = new int[size];
}
~Array(void){
delete[] m_arr;
}
//适用非const对象,返回左值
int& operator[](size_t i){
return m_arr[i];
}
//适用常对象,返回右值
const int& operator[](size_t i)const{
return m_arr[i];
}
private:
int* m_arr;
};
int main(void)
{
Array arr(5);
//arr.operator[](0) = 123;
arr[0] = 123;
const Array& rarr = arr;
cout << rarr[0] << endl;//123
//rarr[0] = 321;//应该error
return 0;
}
7.函数调用操作符:()
1)功能:让对象可以像函数一样去调用
注:对参数的个数、类型和返回类型都没有限制
A a;
a(10,1.23); //a.operator()(10,1.23)
参考代码:
#include <iostream>
using namespace std;
class Func{
public:
int operator()(int a,int b){
return a+b;
}
int operator()(int a){
return a*a;
}
};
int main(void)
{
Func func;
//func.operator()(10,20)
cout << func(10,20) << endl;//30
//func.operator()(10)
cout << func(10) << endl;//100
return 0;
}
8.new/delete操作符
static void* operator new(size_t size){}
static void* operator delete(void* p){}
参考代码:
#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 << "A的new" << endl;
void* pv = malloc(size);
return pv;
}
static void operator delete(void* pv){
cout << "A的delete" << 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;
}
9.操作符重载限制
1)不是所有操作符都能重载,下面操作符不能重载
①作用域限制操作符“::”
②直接成员访问操作符“.”
③直接成员指针解引用操作符“.*”
④条件操作符“?:”
⑤字节长度操作符“sizeof()”
⑥类型信息操作符“typeid()”
2)如果一个操作符所有操作数都是基本类型,则无法重载
3)操作符重载不会改变编译器预定义的优先级
4)操作符重载不能改变操作数的个数
5)无法通过操作符重载发明新的符号
6)只能用成员函数形式的操作符