自增运算符重载 之前我们了解了如何实现对两个复数对象实现相加操作,而我们熟知的运算符比如+=,++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; ++c3; c3++; } 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 ) { Complex temp (*this ) ; ++_dreal; ++_dimage; return temp; } 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 ) { Complex temp (*this ) ; ++_dreal; ++_dimage; return temp; } 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 + 2 iF (x) = 3 + 4 iComplex (double,double) F (x) = 4 + 6 iF (x) = 5 + 8 iF (x) = 6 + 9 iComplex (const Complex&) F (x) = 6 + 9 i~Complex F (x) = 7 + 10 i~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 : 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 << "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; 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 << "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; 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 +2 if (x) = 1 f (x) = 1 -2 if (x) = -1 +2 if (x) = -1 f (x) = -1 -2 if (x) = 2 if (x) = 0 f (x) = -2 i~Complex ~Complex ~Complex ~Complex ~Complex ~Complex ~Complex ~Complex ~Complex
输入运算符重载 实际上就是对对象内的私有成员输入,重构格式与输出类似
class Complex {public : 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 (),'\n' ); 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 (), '\n' ); 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; 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) { cout << "Beyond the Array!" << endl; static char charnull = '\0' ; return charnull; } else { return _data[idx]; } } private : size_t _sz; char * _data; };
此时我们还想模仿string,使得我们的CharArray对象能够通过cout直接输出
class CharArray {public : friend std::ostream& operator <<(std::ostream& os,const CharArray& ca); private : char * _data; size_t _sz; }; std::ostream& operator <<(std::ostream& os,const CharArray& ca) { for (size_t i = 0 ;i < ca.sz ();++i) { os<<ca[i]; } return os; }
代码
#include <iostream> #include <cstring> using std::cout;using std::endl;class CharArray {public : CharArray (const size_t & sz) :_data(new char [sz]()) , _sz(sz) { ; } size_t sz () const { return _sz; } void release () { delete [] _data; _data = nullptr ; } ~CharArray () { if (_data) release (); cout << "~Complex" << endl; } char & operator [] (size_t & idx) { cout << "char& operator []" << endl; if (idx > _sz) { cout << "Beyond the Array!" << endl; static char charnull = '\0' ; return charnull; } else { return _data[idx]; } } friend std::ostream& operator <<(std::ostream& os, CharArray& ca); private : size_t _sz; char * _data; }; std::ostream& operator <<(std::ostream& os, CharArray& ca) { for (size_t i = 0 ; i < ca.sz (); ++i) { os << ca[i] <<' ' ; } return os; } void test0 () { const char * pstr = "Hello World" ; CharArray ca (strlen(pstr) + 1 ) ; for (size_t i = 0 ; i < ca.sz (); ++i) { ca[i] = pstr[i]; } cout << ca << endl; } int main () { test0 (); }
<<重载时对象不能带const的原因
在函数过程中,如果发生了数组越界,那么我们之前所构建的下标重构中会返回charnull,虽然charnull是全局区,但因为引用符号实际上对ca的某个值发生了赋值操作,修改了对象,const不允许这样的操作出现,因此带上const发生了报错