C++之运算符重载

C++内部定义的数据类型(int , float, …)的数据操作可以用运算符号来表示,其使用形式是表达式;用户自定义的类型的数据的操作则用函数表示,其使用形式是函数调用。为了使对用户自定义数据类型的数据的操作与内置的数据类型的数据的操作形式一致,C++提供了运算符的重载,通过把C++中预定义的运算符重载为类的成员函数或者友元函数,使得对用户的自定义数据类型的数据—对象的操作形式与C++内部定义的类型的数据一致。

首先来看一个问题:备注代码定义了一个复数类complex,然后用complex定义了2个复数,如何实现这2个复数的加法呢?

这个问题的解决就需要用到运算符重载的知识,下面详细讲解。

备注代码:

//运算符重载的必要性
#include <iostream>
using namespace std;

class complex		//定义复数类 complex
{
private:
	double real, imag;	//private 成员,分别代表实部和虚部
public:
	complex(double r = 0.0, double i = 0.0)	//构造函数,带缺省参数值
	{
		real = r;
		imag = i;
	}
	void disp()		//成员函数,输出复数
	{
		cout << real << " + " << "i*" << imag << endl;
	}
};
int main()
{
	complex cx1(1.0, 2.0);
	complex cx2(3.0, 4.0);
	complex cxRes = cx1 + cx2;	//错误
	return 0;
}

  

运算符重载规则

  • 运算符是一种通俗、直观的函数,比如: int x = 2 + 3;语句中的“+”操作符
  • 系统本身就提供了很多个重载版本:

    int operator + (int,int);

    double operator + (double,double);

  • 可以重载的运算符有:

    双目运算符+ - * / %

    关系运算符== != < > <= >=

    逻辑运算符|| && +

    单目运算符+ - * &

    自增自减运算符++ --

    位运算符| & ~ ^ << >>

    赋值运算符= += -= *= /= %= &= |= ^= <<= >>=

    空间申请和释放new delete new[] delete[]

    其他运算符() -> ->* , []

  • 不能重载的运算符有:

    成员访问符 .

    成员指针访问运算符 .*

    域运算符 ::

    长度运算符 sizeof

    条件运算符号 ?:

  • 重载操作符必须具有一个类类型或者是枚举类型的操作数

    int operator+(int, int);//不能重载

  • 优先级和结合性是固定的

    操作符的优先级、结合性或操作数个数不能改变 X == Y + Z;

  • 不再具备短路求值特性

    重载操作符并不保证操作数的求值顺序 && || ,

  • 不能臆造并重载一个不存在的运算符,

    如@, #,$等。

预算符重载的方式

运算符重载的方式分为下面3种:

   1. 采用普通函数的重载形式。要求带操作的属性必须时public类型的。

// 普通函数形式 的 运算符重载
#include <iostream>
using namespace std;

class complex		//定义复数类 complex
{
public:
	double real, imag;	//private 成员,分别代表实部和虚部

public:
	complex(double r = 0.0, double i = 0.0)	//构造函数,带缺省参数值
	{
		real = r;
		imag = i;
	}

	void disp()		//成员函数,输出复数
	{
		cout << real << " + " << "i*" << imag << endl;
	}
};

complex operator+(const complex& obj1, const complex& obj2)		//加+的实现
{
	return complex(obj1.real + obj2.real, obj1.imag + obj2.imag);
}

int main()
{
	complex cx1(1.0, 2.0), cx2(3.0, 4.0), cxRes;

	cxRes = cx1 + cx2;	//相当于cx1.operator+(cx2)
	cxRes.disp();

	return 0;
}

  2. 采用友元函数的重载形式。

  • 成员函数形式的运算符声明和实现与成员函数类似,首先应当在类定义中声明该运算符,声明的具体形式为:

    返回类型 operator 运算符(参数列表);

  • 既可以在类定义的同时定义运算符函数使其成为inline型,也可以在类定义之外定义运算符函数,但要使用作用域限定符“::”,类外定义的基本格式为:

    返回类型  类名::operator 运算符(参数列表){ … }

//成员函数形式 的 运算符重载
#include <iostream>
using namespace std;

class complex	//定义复数类 complex
{
private:
	double real, imag;	//private 成员,分别代表实部和虚部

public:
	complex(double r = 0.0, double i = 0.0)	//构造函数,带缺省参数值
	{
		real = r;
		imag = i;
	}

	complex operator+= (const complex &);	//成员函数形式重载加+=

	complex operator+(const complex &);	//成员函数形式重载加+
	complex operator-(const complex &);	//成员函数形式重载减-
	complex operator-();			//成员函数形式重载一元-(取反)
	complex operator*(const complex &);	//成员函数形式重载乘*
	complex operator/(const complex &);	//成员函数形式重载除*

	complex& operator++();	//成员函数形式重载前置++
	complex operator++(int);	//成员函数形式重载后置++

	void disp()			//成员函数,输出复数
	{
		cout << real << " + " << "i*" << imag << endl;
	}
};

complex complex::operator+=(const complex& CC)		//加+=的实现
{
	real += CC.real;
	imag += CC.imag;
	return (*this);
}

complex complex::operator+(const complex& CC)		//加+的实现
{
	return complex(real + CC.real, imag + CC.imag);
}

complex complex::operator-(const complex& CC)		//减-的实现
{
	return complex(real - CC.real, imag - CC.imag);
}

complex complex::operator*(const complex& CC)		//乘*的实现
{
	return complex(real * CC.real - imag * CC.imag, real * CC.imag + imag * CC.real);
}

complex complex::operator/(const complex& CC)		//除/的实现
{
	return complex((real * CC.real + imag * CC.imag) / (CC.real * CC.real + CC.imag * CC.imag),
		(imag * CC.real - real * CC.imag) / (CC.real * CC.real + CC.imag * CC.imag));
}

complex complex::operator-()		//单目-,即取反的实现
{
	return complex(-real, -imag);
}

complex& complex::operator++()	//前置++的实现
{
	cout << "前置++" << endl;
	++real;
	++imag;
	return (*this);
}

complex complex::operator++(int)	//后置++的实现,体会和前置++的区别
{
	cout << "后置++" << endl;
	complex cTemp = (*this);	//最终的返回值的是原来的值,因此需要先保存原来的值
	++(*this);					//返回后原来的值需要加1
	return cTemp;
}

int main()
{
	complex cx1(1.0, 2.0), cx2(3.0, 4.0), cxRes;

	cxRes += cx2;		//相当于cxRes.operator+=(cx2)
	cxRes.disp();
	
	cxRes = cx1 + cx2;	//相当于cx1.operator+(cx2)
	cxRes.disp();
	
	cxRes = cx1 - cx2;	//相当于cx1.operator-(cx2)
	cxRes.disp();
	
	cxRes = cx1 * cx2;	//相当于cx1.operator*(cx2)
	cxRes.disp();
	
	cxRes = cx1 / cx2;	//相当于cx1.operator/(cx2)
	cxRes.disp();
	
	cxRes = -cx1;		//相当于cx1.operator-()
	cxRes.disp();
	
	cout << endl;
	
	complex cx3(1.0, 1.0), cx4(5.0, 5.0);
	
	cxRes = ++cx3;		//相当于cx3.operator++()
	cxRes.disp();
	cx3.disp();

	cout << endl;
	
	cxRes = cx4++;		//相当于cx4.operator++(0)
	cxRes.disp();
	cx4.disp();

	cout << endl;
	
	//注意下述语句在友元函数形式和成员函数形式中的对比。
	cxRes = cx1 + 5;	//相当于cx1.operator+(5) 或 cx1.operator+(complex(5))
	cxRes.disp();

//	cxRes = 5 + cx1;	//错误. 相当于5.operator+(cx1);
//	cxRes.disp();

	return 0;
}

    3. 采用成员函数的重载形式.

  • 用成员函数重载双目运算符时,左操作数无须用参数输入,而是通过隐含的this指针传入,这种做法的效率比较高
  • 此外,操作符还可重载为友元函数形式,这将没有隐含的参数this指针。对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。
  • 重载为友元函数的运算符重载函数的声明格式为:

    friend 返回类型operator 运算符 (参数表);

//友员函数形式 的 运算符重载
#include <iostream>
using namespace std;

class complex		//定义复数类complex
{
private:
	double real,imag;	//private成员,分别代表实部和虚部

public:
	complex(double r=0.0,double i=0.0)	//构造函数,带缺省参数值
	{
		real=r;
		imag=i;
	}

	friend complex operator + (const complex &,const complex &);	//友元函数形式重载加+
	friend complex operator - (const complex &,const complex &);	//友元函数形式重载减-
	friend complex operator - (const complex &);	//友元函数形式重载一元-(取反)
	friend complex operator * (const complex &,const complex &);	//友元函数形式重载乘*
	friend complex operator / (const complex &,const complex &);	//友元函数形式重载除*
	friend complex& operator ++(complex &);		//友元函数形式重载前置++
	friend complex operator ++(complex &,int);		//友元函数形式重载后置++

	void disp()														//成员函数,输出复数
	{
		cout<<real<<" + "<<"i*"<<imag<<endl;
	}
};

complex operator +(const complex& C1,const complex& C2)		//加+的实现
{
	return complex(C1.real + C2.real, C1.imag + C2.imag);
}

complex operator -(const complex& C1,const complex& C2)		//减-的实现
{
	return complex(C1.real - C2.real, C1.imag - C2.imag);
}

complex operator -(const complex& C1)		//单目-,即取反的实现
{
	return complex(-C1.real, -C1.imag);
}

complex operator *(const complex& C1,const complex& C2)		//乘*的实现
{
	return complex(C1.real * C2.real - C1.imag * C2.imag, C1.real * C2.imag + C1.imag * C2.real);
}

complex operator /(const complex& C1,const complex& C2)		//除*的实现
{
	return complex((C1.real * C2.real + C1.imag + C2.imag) / (C2.real * C2.real + C2.imag * C2.imag),
		(C1.imag * C2.real - C1.real * C2.imag) / (C2.real * C2.real + C2.imag * C2.imag));
}

complex& operator ++(complex& C1)		//前置++的实现
{
	cout << "前置++" << endl;
	C1.real += 1;
	C1.imag += 1;
	return C1;
}

complex operator ++(complex& C1,int)	//后置++的实现,体会和前置++的区别
{
	cout << "后置++" << endl;
	complex ctemp = C1;
	++C1;
	return ctemp;
}

int main()
{
	complex cx1(1.0, 2.0), cx2(3.0, 4.0), cxRes;
	
	cxRes = cx1 - cx2;	//相当于operator-(cx1, cx2)
	cxRes.disp();
	
	cxRes = -cx1;		//相当于operator-(cx1)
	cxRes.disp();
	
	cxRes = cx1 + cx2;	//相当于operator+(cx1, cx2)
	cxRes.disp();
	
	cxRes = cx1 * cx2;	//相当于operator*(cx1, cx2)
	cxRes.disp();
	
	cxRes = cx1 / cx2;	//相当于operator/(cx1, cx2)
	cxRes.disp();
	
	complex cx3(1.0, 1.0), cx4(5.0, 5.0);
	
	cxRes = ++cx3;		//相当于operator++(cx3)
	cxRes.disp();
	cx3.disp();
	
	cxRes = cx4++;		//相当于operator++(cx4, 0)
	cxRes.disp();
	cx4.disp();
	
	//注意下述语句在友元函数形式和成员函数形式的对比。
	cxRes = cx1 + 5;	//相当于operator+(cx1, 5);
	cxRes.disp();

	cxRes = 5 + cx1;	//相当于operator+(5, cx1);
	cxRes.disp();

	return 0;
}

  

友元函数形式和成员函数形式的比较

  • 对于绝大多数可重载操作符来说,两种重载形式都是允许的。但对下标运算符[] 、赋值运算符=、函数调用运算符()、指针运算符->,只能使用成员函数形式
  • 对于如下代码:

    complex c1(1.0, 2.0), cRes;

    cRes = c1 + 5; //#1

    cRes = 5 + c1; //#2

  • 友元函数形式重载的都是合法的,可转换成:

    cRes = operator+(c1, 5); //#1

    合法 cRes = operator+(5, c1); //#2 合法

  • 但成员函数形式的重载,只有语句#1合法,语句#2非法

    cRes = c1.operator+(complex(5)); //#1可能合法

    cRes = 5.operator+(c1); //#2 非法,5不会隐式转换成complex

对运算符重载的补充说明

  • 运算符重载可以改变运算符内置的语义,如以友元函数形式定义的加操作符:
complex operator +(const complex& C1,const complex& C2)
{
    return complex(C1.real-C2.real,C1.imag-C2.imag);
}
  • 明明是加操作符,但函数内却进行的是减法运算,这是合乎语法规则的,不过却有悖于人们的直觉思维,会引起不必要的混乱,因此,除非有特别的理由,尽量使重载的运算符与其内置的、广为接受的语义保持一致。

几种运算符的重载

赋值运算符  =

  • 赋值运算是一种很常见的运算,如果不重载赋值运算符,编译器会自动为每个类生成一个缺省的赋值运算符重载函数,先看下面的语句:

    对象1=对象2;

  • 实际上是完成了由对象2各个成员到对象1相应成员的复制,其中包括指针成员,这和第8章中复制构造函数和缺省复制构造函数有些类似,如果对象1中含指针成员,并且牵扯到类内指针成员动态申请内存时,问题就会出现。
  • 注意下述两个代码的不同:

    类名 对象1=对象2; //复制构造函数

    类名 对象1(对象2);

    和

    类名 对象1; //默认构造函数

    对象1=对象2; //赋值运算符函数

//9-9 赋值运算符重载。如果没有,执行时会出错.
#include <iostream>
using namespace std;

class computer
{
private:
	char *brand;	//字符指针brand
	float price;

public:
	computer()		//无参构造函数
	{
		brand = NULL;	//brand初始化为NULL
		price = 0;
		cout << "无参构造函数被调用" << endl;
	}

	computer(const char* sz,float p)
	{
		brand = new char[strlen(sz)+1];	//构造函数中为brand分配一块动态内存
		strcpy(brand, sz);				//字符串复制
		price = p;
		cout << "带参构造函数被调用" << endl;
	}

	computer(const computer& cp)		//复制构造函数
	{
		brand = new char[strlen(cp.brand) + 1];	//为brand分配动态内存
		strcpy(brand, cp.brand);		//字符串复制
		price = cp.price;
		cout << "复制构造函数被调用" << endl;
	}

//	//如果我们没有重载=,则系统会隐式的重载成如下形式:
//	computer &operator=(const computer &cp)
//	{
//		price = cp.price;
//		brand = cp.brand;
//		cout<<"系统默认赋值函数被调用"<<endl;
//		return (*this);
//	}
//
//	//应该使用下述函数取代上述系统隐式的定义
//	computer &operator=(const computer &cp)		//成员函数形式重载赋值运算符
//	{
//		if (this==&cp)	//首先判断是否是自赋值,是的话返回当前对象
//			return  (*this);
//
//		price=cp.price;	//如果不是自赋值,先对price赋值
//		delete[] brand;	//防止内存泄露,先释放brand指向的内容
//		brand=new char[strlen(cp.brand)+1];	//为brand重新开辟一块内存空间
//		if (brand!=NULL)			//如果开辟成功
//		{
//			strcpy(brand,cp.brand);	//复制字符串
//		}
//		cout<<"赋值运算符重载函数被调用"<<endl;
//
//		return  (*this);										//返回当前对象的引用,为的是实现链式赋值
//	}

	~computer()	//析构函数,释放动态内存,delete[] NULL不会出错
	{
		delete[] brand;
		cout << "析构函数被调用" << endl;
	}

	void print()	//成员函数,输出信息
	{
		cout << "品牌:" << brand << endl;
		cout << "价格:" << price << endl;
	}
};

int main()
{
	computer com1("Dell", 2000);	//调用含参构造函数声明对象com1
	computer com2 = com1;			//调用复制构造函数

	if (true)
	{
		computer com3;				//调用无参构造函数
		com3 = com1;				//调用赋值运算符重载函数
	}

	return 0;
}

  

函数调用运算符    ( )

  • 函数调用运算符()同样只能重载为成员函数形式。其形式为:

    返回类型 operator()(arg1,arg2,……)

  参数个数可以有多个,没有限制。

  • 针对如下定义:

    void computer::operator()(){};

    int computer::operator()(int x){};

    char computer::operator()(char x, char y){};

  • 可以这样调用:

    computer com1;

    int z = com1(3200);

    char c = com1(‘a’, ‘b’);

  • 一个类如果重载了函数调用operator(),就可以将该类对象作为一个函数使用,这样的类对象也称为函数对象。函数也是一种对象,这是泛型思考问题的方式。 
//重载函数调用运算符()
#include <iostream>
using namespace std;

class Demo		//Demo类定义
{
public:
	double operator()(double x, double y)	//重载函数调用符(),两个double型参数
	{
		return x > y ? x : y;		//返回两个参数中较大的一个
	}

	double operator()(double x, double y, double z)	//重载函数调用符(),3个double型参数
	{
		return (x + y) * z;	//将前两个相加,与第3个参数相乘,返回最后的结果
	}
};

void main()
{
	Demo de;											//声明一个类对象
	cout << de(2.5, 0.2) << endl;	//可以将对象像函数一样使用
	cout << de(1.2, 1.5, 7.0) << endl;
}

  

下标运算符  [ ]

  • 下标运算符是个二元运算符,C++编译器将表达式

    sz[x];

  解释为

    sz.operator[](z);

  • 一般情况下,下标运算符的重载函数原型如下:

    返回类型& operator[ ](参数类型);

  • 下标运算符的重载函数只能有一个参数,不过该参数并没有类型限制,任何类型都可以,如果类中未重载下标运算符,编译器将会给出下标运算符的缺省定义,此时,参数必须是int型,并且要声明数组名才能使用下标变量,如

    computer com[3];

  • 则com[1]等价于com.operator[](1),如果[]中的参数类型非int型,或者非对象数组要使用下标运算符时,需要重载下标运算符[]。
//9-11 下标运算符[]
#include <iostream>
using namespace std;

class CharSZ	//类CharSZ的定义
{
private:		//private成员列表
	int iLen;
	char *pBuf;

public:
	CharSZ(int size)	//构造函数
	{
		iLen= size;
		pBuf = new char[iLen];	//开辟一块动态内存,字符数组
	}

	~CharSZ()			//析构函数
	{
		delete pBuf;	//释放申请的动态内存
	}

	int GetLen()		//读取private成员iLen的值
	{
		return iLen;
	}

	char& operator [](int i);	//以成员函数形式重载下标运算符
};

char & CharSZ::operator[](int i)//下标运算符重载的实现
{
	static char szNull = '\0';	//用于返回空字符时, 由于返回类型为char &,不能直接return '\0';
	if (i < iLen && i >= 0)	//如果参数i在有效范围内
	{
		return pBuf[i];	//返回字符数组的第i+1个元素
	}
	else
	{
		cout << "下标越界" << endl;	//参数i不合法
		return szNull;	//输出空字符. 不能直接return '\0';
	}
}

int main()
{
	char *sz = "Hello, world!";
	CharSZ de(strlen(sz) + 1);   //对象de中申请的动态内存大小为n,可存放n-1个有效字符(除开'\0')

	//将sz的内容复制给de
	int i;
	for (i = 0; i < (strlen(sz) + 1); i++)
	{
		de[i] = sz[i];
	}

	//逐个输出de的值
	for (i = 0; i < de.GetLen(); i++)
	{
		cout << de[i];
	}

	cout << endl;
	return 0;
}

  

new 和delete的重载

  • 通过重载new和delete,我们可以自己实现内存的管理策略。new和delete只能重载为类的静态运算符而且重载时,无论是否显示指定static关键字,编译器都认为是静态的运算符重载函数
  • 重载new时,必须返回一个void *类型的指针,它可以带多个参数,但第1个参数必须是size_t类型,该参数的值由系统确定。
static void * operator new(size_t nSize)
{
  cout << "new操作符被调用, size = " << nSize << endl;
  void * pRet = new char[nSize]; return pRet;
}
  • 重载delete时必须返回void类型,它可以带有多个参数,第1个参数必须是要释放的内存的地址void *,如果有第2个参数,它必须为size_t类型。
static void operator delete(void * pVoid)
{
  cout << "delete操作符被调用." << endl;
  delete [] pVoid;
}

代码:

//new 和 delete 运算符重载
#include <iostream>
using namespace std;

class CStudent
{
public:
	int iId;
	char szName[10];

public:
	static void * operator new(size_t nSize)
	{
		cout << "new 操作符被调用, size = " << nSize << endl;
		void * pRet = new char[nSize];
		return pRet;
	}

	static void operator delete(void * pVoid)
	{
		cout << "delete 操作符被调用." << endl;
		delete [] pVoid;
	}
};

int main()
{
	CStudent *pStu = new CStudent();

	pStu->iId = 101;
	strcpy(pStu->szName, "Tony");

	delete pStu;

	return 0;
}

  

输入>>输出<<的重载

  • >>和<<运算符只能重载为友元函数形式。
  • 对操作符<<的重载
friend ostream& operator<<(ostream& os,const Complex& C1)
{
  os<<C1.real<<"+i*"<<C1.imag<<endl;
  return os;
}
  • 对操作符>>的重载
friend istream& operator>>(istream& is,Complex& C1)
{
  is>>C1.real; while (is.get()!='*‘);
  is>>C1.imag; return is;
} 
//对操作符>>的重载
#include <iostream>
using namespace std;


class Complex
{
private:
	double imag;		//虚部
	double real;		//实部
public:
	Complex(double r=0.0,double i=0.0)	//构造函数
	{
		real=r;
		imag=i;
	}
	friend ostream& operator<<(ostream& ,Complex& );		//友元函数声明
	friend istream& operator>>(istream& ,Complex& );
};

ostream& operator<<(ostream& os,Complex& C1)			//对操作符<<的重载
{
	os<<C1.real<<"+i*"<<C1.imag<<endl;
	return os;
}

istream& operator>>(istream& is,Complex& C1)			//对操作符>>的重载
{
	is>>C1.real;
	while (is.get()!='*')
	{
	}
	is>>C1.imag;
	return is;
}

int main()
{
	Complex c1(2.5,3.1);
	cin>>c1;
	cout<<c1;
	return 0;
}

  

指针运算符->的重载

  • 箭头运算符必须是类的成员函数
  • 指针运算符返回值必须是一个指针,或者是一个重载了箭头运算符的对象。
    • 如果返回的是一个指针将调用内置的箭头运算符。执行相当于

        (*(obj.operator->()).data;

    • 如果返回是一个重载了箭头运算符的对象,则继续对该对象调用其重载了的箭头运算符,直到返回的是一个指针,将对该指针调用a)的操作。操作相当于

        (*(obj.operator->().operator->())).data;

  • 总的来说重载的箭头运算符就是为了改变从哪个对象中获取成员
//->操作符重载

#include <iostream>
using std::cout;
using std::endl;

class Data
{
public:
    Data(){cout << "Data()" <<endl;}
    ~Data(){cout<< "~Data()"<< endl;}
    int length()
    {
	return 5;
    }
private:

};

class DataPtr
{
public:
    DataPtr()
	:_pData(new Data)
    {
	cout<< "DataPtr() " << endl; 
    }
    ~DataPtr()
    {
	cout << "~DataPtr()" << endl;
	delete _pData;
    }
    //指针访问运算符
    Data *operator->()
    {
	return _pData;
    }
    //解引用运算符
    Data& operator*()
    {
	return *_pData;
    }
private:
    Data *_pData;
};

class ThirdLayer
{
public:
    ThirdLayer()
    {
	cout << "ThirdLayer()" << endl;
    }
    DataPtr &operator->()
    {
	return _dp;
    }
    ~ThirdLayer()
    {
	cout << "~ThirdLayer()" << endl;
    }
private:
    DataPtr _dp;
};
int main()
{
    DataPtr dp;
    //下面两个写法效果是一样的 
    cout << dp->length() << endl;
    cout << (dp.operator->())->length() << endl;
    cout<<endl;

    cout << (*dp).length()<< endl;
    cout <<  endl;

    ThirdLayer t1;
    cout <<  t1->length() << endl;
    cout << ((t1.operator->()).operator->())->length() << endl;
    cout <<  endl;
    return 0;
}

   

完整代码:

 ///**********************************************
 /// @file    reload.cc
 /// @author  alex([email protected])
 /// @date    2018-06-13 23:15:55
 ///**********************************************/
 
#include <iostream>
#include <limits>
using namespace std;
 
class Complex
{
public:
    Complex(double dreal=0,double dimag=0)
	:_dreal(dreal)
	 ,_dimag(dimag)
    {}
    void display()
    {
	if(_dreal == 0&& _dimag !=0)
	    cout << _dimag << "i" << endl;
	else{
	    cout << _dreal; 
	    if(_dimag>0)
	    {
		cout << "+" << _dimag << "i" << endl;
	    }else if(_dimag < 0)
	    {
		cout << "-" << _dimag*(-1) << "i" << endl;
	    
	    }else{
		cout << endl;
	    }
	}
    }
    //成员函数重载
    //复合赋值运算符推荐以成员函数形式进行重载
    Complex &operator+=(const Complex &rhs)
    {
	_dreal += rhs._dreal;
	_dimag += rhs._dimag;
	return *this;
    }
    friend Complex operator+(const Complex &lhs,const Complex &rhs);
    friend bool operator<(const Complex &lhs,const Complex &rhs);//关系运算符(<、>、<=、>=、=)
    friend std::ostream & operator<<(std::ostream & os,const Complex & rhs);
    friend std::istream & operator>>(std::istream & is,Complex & rhs);
    //前置++比后置++效率高
    //前置++推荐以成员函数形式重载
    Complex & operator++()
    {
	++_dreal;
	++_dimag;
	return *this;
    }
    Complex operator++(int)//int 是为了与前置++区分,是一个标记
    {
	Complex tmp(*this);
	++_dreal;
	++_dimag;
	return tmp;
    }

private:
    double _dreal;
    double _dimag;
};
//输入输出流不能以成员函数进行重载
//输入输出流运算符不能时成员函数进行重载
//因为输入输出流的第一个形参必须时流对象
//而成员函数的第一个形参时隐含的this指针
//这就引起了冲突
//operator<<()
std::ostream &  operator<<(std::ostream &os,const Complex &rhs)
{
    cout<< "std::ostream & operator <<" <<endl;
    if(rhs._dreal == 0 && rhs._dimag !=0)
        os << rhs._dimag << "i" << endl; 
    else{
        os << rhs._dreal;
        if(rhs._dimag > 0)
        {
            os << "+" << rhs._dimag << "i" << endl;

        }else if(rhs._dimag > 0)
            os << "-" << rhs._dimag *(-1) << "i" << endl;
        else os << endl;
    }
    return os;   
}
void readDouble(std::istream& is,double& value)
{
    cout << "is has corrupted1" << endl;
    while(is>>value)
    {
	if(is.bad())
	{
	    cout << "is has corrupted1" << endl;
	    return ;
	}else if(is.fail())
	{
	    is.clear();
	    is.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
	    cout << "input a number:" ;
	}else{
	    break;
	}
    }
}
std::istream & operator>>(std::istream &is,Complex &rhs)
{
    //is >> rhs._dreal;
    //is >> rhs._dimag;
    readDouble(is,rhs._dreal);
    readDouble(is,rhs._dimag);
    return is;
}
#if 0
//运算符重载的功能不能针对内置数据
//只能作用域自定义类类型和枚举类型
int operator+(int a,int b){}
#endif
Complex operator+(const Complex &lhs,const Complex &rhs)
{
    return Complex(lhs._dreal + rhs._dreal , lhs._dimag + rhs._dimag);
}
bool operator<(const Complex &lhs,const Complex &rhs)
{
    return lhs._dreal < rhs._dreal;
}

void test0(void)
{
    Complex c1(1,2);
    Complex c2(3,4);
    Complex c3 = c1+c2;
    c3.display();
    Complex c4 (0,0);
    c4.display();
    Complex c5 (0,-1);
    c5.display();
}
void test1(void)
{
    int a=3,b=4;
    a+=b;
    ++a;//前置++
    a++;//后置++
    Complex c1(1,-2);
    c1.display();
    (++c1).display();
    c1.display();
    (c1++).display();
    c1.display();
}
void test2(void)
{
    Complex c1(1,2);
    c1.display();
    Complex c2=c1+5;
    c2.display();
    Complex c3 = 5+c1;
    c3.display();
}
void test3()
{
    Complex c1(1,-2);
    cout << "c1= " <<c1 <<  endl;
}
int main()
{
    test3();
    return 0;
}

  

  

猜你喜欢

转载自www.cnblogs.com/cthon/p/9181404.html