您现在的位置是:首页 >技术杂谈 >运算符重载(重构)网站首页技术杂谈
运算符重载(重构)
简介运算符重载(重构)
自增运算符重载
之前我们了解了如何实现对两个复数对象实现相加操作,而我们熟知的运算符比如+=,++i,i++等操作暂时还没能正常使用
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
class Complex {
public:
Complex(const double& dreal, const double& dimage)
:_dreal(dreal)
, _dimage(dimage)
{
cout << "Complex(double,double)" << endl;
}
void print()
{
cout << "F(x) = " << _dreal << " + " << _dimage << 'i' << endl;
}
Complex(const Complex& c)
:_dreal(c._dreal)
, _dimage(c._dimage)
{
;
}
~Complex()
{
cout << "~Complex" << endl;
}
friend Complex operator + (const Complex& lhs, const Complex& rhs);
private:
double _dreal;
double _dimage;
};
Complex operator + (const Complex& lhs, const Complex& rhs)
{
Complex temp(lhs._dreal + rhs._dreal, lhs._dimage + rhs._dimage);
return temp;
}
void test0()
{
Complex c1(1, 2);
Complex c2(3, 4);
Complex c3 = c1 + c2;
c3 += c1;//error
++c3;//error
c3++;//error
}
int main()
{
test0();
return 0;
}
重构+=操作
class Complex{
public:
Complex& operator += (const Complex& rhs)
{
this->_dreal += rhs._dreal;
this->_dimage += rhs._dimage;
return *this;
}
private:
double _dreal;
double _dimage;
};
重构++i操作
class Complex{
public:
Complex operator ++()
{
_dreal++;
_dimage++;
return *this;
}
private:
double _dreal;
double _dimage;
};
重构i++操作
class Complex{
public:
Complex operator ++(int)//int仅仅是用来标识重构的是i++操作,int没有任何实际意义
{
Complex temp(*this);
++_dreal;
++_dimage;
return temp;//还原i++操作,i++为先反应后自增
}
private:
double _dreal;
double _dimage;
};
上述操作中有一些函数定义中+=和++i带有引用符号,而i++则没有带,原因是i++返回的是临时变量,为右值无法进行取地址操作,而前两个返回的是this指针
由此也看出++i操作比i++操作要简便不少
总实现代码
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
class Complex {
public:
Complex(const double& dreal, const double& dimage)
:_dreal(dreal)
, _dimage(dimage)
{
cout << "Complex(double,double)" << endl;
}
void print() const
{
cout << "F(x) = " << _dreal << " + " << _dimage << 'i' << endl;
}
Complex(const Complex& c)
:_dreal(c._dreal)
, _dimage(c._dimage)
{
cout << "Complex(const Complex&)" << endl;
}
~Complex()
{
cout << "~Complex" << endl;
}
friend Complex operator + (const Complex& lhs, const Complex& rhs);
Complex& operator += (const Complex& rhs)
{
this->_dreal += rhs._dreal;
this->_dimage += rhs._dimage;
return *this;
}
Complex& operator ++()
{
_dreal++;
_dimage++;
return *this;
}
Complex operator ++(int)//int仅仅是用来标识重构的是i++操作,int没有任何实际意义
{
Complex temp(*this);
++_dreal;
++_dimage;
return temp;//还原i++操作,i++为先反应后自增
}
private:
double _dreal;
double _dimage;
};
Complex operator + (const Complex& lhs, const Complex& rhs)
{
Complex temp(lhs._dreal + rhs._dreal, lhs._dimage + rhs._dimage);
return temp;
}
void test0()
{
Complex c1(1, 2);
Complex c2(3, 4);
c1.print();
c2.print();
Complex c3 = c1 + c2;
c3.print();
c3 += c1;
c3.print();
(++c3).print();
(c3++).print();
c3.print();
}
int main()
{
test0();
return 0;
}
Complex(double,double)
Complex(double,double)
F(x) = 1 + 2i
F(x) = 3 + 4i
Complex(double,double)
F(x) = 4 + 6i
F(x) = 5 + 8i
F(x) = 6 + 9i
Complex(const Complex&)
F(x) = 6 + 9i
~Complex
F(x) = 7 + 10i
~Complex
~Complex
~Complex
输入输出重载运算符
重构输入输出的操作就在于他们的输入输出运算符>>,<<
输出运算符重载
首先我们先对print成员函数优化一下,使他复数的表现形式更加标准规范
#include <iostream>
using std::endl;
using std::cout;
class Complex {
public:
Complex(const double& dreal, const double& dimage)
:_dreal(dreal)
, _dimage(dimage)
{
cout << "Complex(double,double)" << endl;
}
~Complex()
{
cout << "~Complex" << endl;
}
void print() const
{
cout << "f(x) = ";
if (!_dreal && !_dimage) cout << 0;
if (_dreal)
{
cout << _dreal;
if (_dimage > 0) cout << "+";
}
if (_dimage)
{
if (_dimage == 1) cout << "i";
else if (_dimage == -1) cout << "-i";
else cout << _dimage << 'i';
}
cout << endl;
}
private:
double _dreal;
double _dimage;
};
void test1()
{
Complex c1(1, 2)
, c2(1, 0)
, c3(1, -2)
, c4(-1, 2)
, c5(-1, 0)
, c6(-1, -2)
, c7(0, 2)
, c8(0, 0)
, c9(0, -2);
c1.print();
c2.print();
c3.print();
c4.print();
c5.print();
c6.print();
c7.print();
c8.print();
c9.print();
}
int main()
{
test1();
return 0;
}
可以发现在我们输出一连串对象的时候会频繁调用print函数(因为调用需要一个.所以用起来非常难受)
<< 也是一种运算符,我们可以利用重构<<的方法省去调用函数的操作,观察可得,重构<<运算符需要两个参数,类似于cout的输出函数和其右边相应的值
那么我们就可以得到重构<<的运算符重载声明
ostream& operator <<(ostream& os,const Complex& rhs)
class Complex{
public:
//在类中定义时的写法
//std::ostream& operator <<(std::ostream& os)
//该写法将右边的参数当做隐藏参数放在了第一个参数的位置上,违反了操作数的左右位置,于是我们更希望使用friend友元的方式完整的写出参数列表
friend std::ostream& operator <<(std::ostream& os,const Complex& rhs);
private:
double _dreal;
double _dimage;
};
std::ostream& operator <<(std::ostream& os,const Complex& rhs)
{
//先把输出的值放在os流中(单独一个cout)
os << "f(x) = ";
if (!rhs._dreal && !rhs._dimage) os << 0;
if (rhs._dreal)
{
os << rhs._dreal;
if (rhs._dimage > 0) os << "+";
}
if (rhs._dimage)
{
if (rhs._dimage == 1) os << "i";
else if (rhs._dimage == -1) os << "-i";
else os << rhs._dimage << 'i';
}
os << endl;
//将os流中的数据全数输出
return os;
}
优化后代码
#include <iostream>
using std::endl;
using std::cout;
class Complex {
public:
Complex(const double& dreal, const double& dimage)
:_dreal(dreal)
, _dimage(dimage)
{
cout << "Complex(double,double)" << endl;
}
~Complex()
{
cout << "~Complex" << endl;
}
friend std::ostream& operator <<(std::ostream& os, const Complex& rhs);
private:
double _dreal;
double _dimage;
};
std::ostream& operator <<(std::ostream& os, const Complex& rhs)
{
//先把输出的值放在os流中(单独一个cout)
os << "f(x) = ";
if (!rhs._dreal && !rhs._dimage) os << 0;
if (rhs._dreal)
{
os << rhs._dreal;
if (rhs._dimage > 0) os << "+";
}
if (rhs._dimage)
{
if (rhs._dimage == 1) os << "i";
else if (rhs._dimage == -1) os << "-i";
else os << rhs._dimage << 'i';
}
os << endl;
//将os流中的数据全数输出
return os;
}
void test1()
{
Complex c1(1, 2)
, c2(1, 0)
, c3(1, -2)
, c4(-1, 2)
, c5(-1, 0)
, c6(-1, -2)
, c7(0, 2)
, c8(0, 0)
, c9(0, -2);
cout << c1 << c2 << c3 << c4 << c5 <<c6 << c7 << c8 << c9 << endl;
}
int main()
{
test1();
return 0;
}
Complex(double,double)
Complex(double,double)
Complex(double,double)
Complex(double,double)
Complex(double,double)
Complex(double,double)
Complex(double,double)
Complex(double,double)
Complex(double,double)
f(x) = 1+2i
f(x) = 1
f(x) = 1-2i
f(x) = -1+2i
f(x) = -1
f(x) = -1-2i
f(x) = 2i
f(x) = 0
f(x) = -2i
~Complex
~Complex
~Complex
~Complex
~Complex
~Complex
~Complex
~Complex
~Complex
输入运算符重载
实际上就是对对象内的私有成员输入,重构格式与输出类似
class Complex{
public:
friend std::istream& operator >>(std::istream& is,Complex& rhs);//不能带const因为对象的值需要修改
private:
double _dreal;
double _dimage;
};
void readDouble(std::istream& is,double& number)
{
while(is>>number,!is.eof())
{
if(is.bad())
{
cout<<"istream has broken"<<endl;
return;
}
if(is.fail())
{
is.clear();
//第一个参数为流的最大输入字节数
is.ignore(std::numeric_limits<std::streamsize>::max(),'
');
cout<<"please input a interger number"<<endl;
}
else
{
cout<<"number:"<<number<<endl;
return;
}
}
}
std::istream& operator >>(std::istream& is.Complex& rhs)
{
readDouble(rhs._dreal);
readDouble(rhs._dimage);
}
代码
#include <iostream>
using std::endl;
using std::cout;
class Complex {
public:
Complex()
:_dreal(0)
,_dimage(0)
{
cout<<"Complex()"<<endl;
}
Complex(const double& dreal, const double& dimage)
:_dreal(dreal)
, _dimage(dimage)
{
cout << "Complex(double,double)" << endl;
}
~Complex()
{
cout << "~Complex" << endl;
}
friend std::istream& operator >>(std::istream& is, Complex& rhs);
private:
double _dreal;
double _dimage;
};
void readDouble(std::istream& is, double& number)
{
while (is >> number, !is.eof())
{
if (is.bad())
{
cout << "istream has broken" << endl;
return;
}
if (is.fail())
{
is.clear();
//第一个参数为流的最大输入字节数
is.ignore(std::numeric_limits<std::streamsize>::max(), '
');
cout << "please input a interger number" << endl;
}
else
{
cout << "number:" << number << endl;
return;
}
}
}
std::istream& operator >>(std::istream& is,Complex& rhs)
{
readDouble(is,rhs._dreal);
readDouble(is,rhs._dimage);
return is;
}
void test1()
{
Complex c1;
std::cin>>c1;
}
int main()
{
test1();
return 0;
}
函数调用重载
函数调用重载是一种比较特殊的函数重载,之前的函数重载是对同一名称的函数以不同参数为根据重载,函数调用重载在此基础上,通过对象来进行调用
#include <iostream>
using std::cout;
using std::endl;
class Func {
public:
Func()
:count(0)
{
;
}
int operator()(int x, int y)
{
++count;
return x + y;
}
int operator()(int x, int y, int z)
{
++count;
return x + y + z;
}
private:
int count;
};
int add(int x, int y)
{
return x + y;
}
int add(int x, int y, int z)
{
return x + y + z;
}
void test0()
{
Func fun;
//Func两种调用方式
cout << fun(1, 2) << endl;
cout << fun(1, 2, 3) << endl;
cout << fun.operator()(1, 2) << endl;
cout << fun.operator()(1, 2, 3) << endl;
//普通函数调用以及重载
cout << add(1, 2) << endl;
cout << add(1, 2, 3) << endl;
//指针调用
typedef int (*aptr)(int, int);
aptr addptr = add;
cout << addptr(1, 2) << endl;
}
int main()
{
test0();
}
下标访问运算符重载
在我们采用string类创建对象时,我们发现string对象可以直接用下标访问对应的字符,并且可以进行修改,接下来我们可以尝试模仿string类的这一特点来重载下表访问运算符
#include <iostream>
#include <cstring>
using std::cout;
using std::endl;
class CharArray{
public:
CharArray(size_t& sz)
:_data(new char[sz]())
,_sz(sz)
{
;
}
int sz()
{
return _sz;
}
void release()
{
delete [] _data;
_data = nullptr;
}
~CharArray()
{
if(_data) release();
cout<<"~Complex"<<endl;
}
private:
size_t _sz;
char* _data;
};
void test0()
{
const char* pstr = "Hello World";
CharArray(strlen(pstr) + 1);
for(int i = 0;i < ca.sz();++i)
{
ca[i] = pstr[i];
}
}
int main()
{
test0();
}
此时报错显示 没有与这些操作数匹配的 “[]” 运算符
所以我们还需要重构[]运算符
class CharArray{
public:
char& operator [](size_t idx)
{
cout << "char& operator []" << endl;
if (idx > _sz)//因为类型为size_t,不会有负数的情况
{
cout << "Beyond the Array!" << endl;
static char charnull = '