C++核心编程——运算符重载

运算符重载的方法

运算符重载的方法是定义一个重载运算符的函数,使指定运算符不能能实现原有的功能,还能实现在函数中指定新的功能。运算符重载的实质是函数的重载。
重载运算符的函数一般格式如下:
函数类型 operator 运算符名称(形参表)
{ 对运算符的重载处理 }

在这里插入图片描述
典例:对运算符 “+” 实现重载,使之能用于两个复数相加。

#include <iostream>
using namespace std;
class Complex{
public:
	Complex(){real=0;imag=0;}
	//自定义有参构造 无参构造不再提供,若要用,需要自定义 
	Complex(int, int);
	Complex operator+(Complex &c);
	void display();
	
	
private:
	int real;
	int imag;
};

Complex::Complex(int real, int imag)
{
	this->real = real;
	this->imag = imag;
}

Complex Complex::operator+(Complex &c)
{
	Complex tempc;
	tempc.real = real + c.real;
	tempc.imag = imag + c.imag;
	return tempc;
}
void Complex::display()
{
	cout << "(" << real << "," << imag << "i)" << endl;
}
int main()
{
	Complex c1(3,4);
	Complex c2(5,-10);
	Complex c3;
	c3 = c1 + c2; 	//相当于:c3 = c1.operator+(c2); 
	cout << "c1=";		c1.display();
	cout << "c2=";		c2.display();
	cout << "c1+c2=";	c3.display();
	return 0;
} 

说明:

  • 自定义有参构造函数,则无参构造不再提供,若要用,需要重新自定义
  • 程序 c3 = c1 + c2 相当于 c3 = c1.operator+(c2); ,使用运算符重载能使用户程序易于编写,阅读和维护。

运算符重载函数作成员函数与友元函数

在这里插入图片描述
如果将运算符重载函数作为成员函数,它可以通过this指针自由地访问本类的数据成员,因此可以少写一个函数的参数。必须要求运算表达式(如c1+c2)中第1个参数即运算符左侧的操作数)是一个类对象而且与运算符函数的类型相同。因为必须通过类的对象去调用该类的成员函数,而且只有运算符重载函数返回值与该对象同类型,运算结果才有意义。

  • 如果想要计算复数+整数,如c1+i,需要重新重载运算符
    Complex Complex::operator+(int i)
    {
    	Complex tempc;
    	tempc.real = real + i;
    	tempc.imag = imag;
    	return tempc;
    }
    
  • 如果想要计算整数+复数,如i+c1, 则第一个参数不是类对象,必须使用友元函数重载运算符。
    Complex operator+(int i, Complex &c)
    {
    	Complex tempc;
    	tempc.real = i + c.real;
    	tempc.imag = c.imag;
    	return tempc;
    }
    
  • 一般将双目运算符重载为友元函数
    Complex operator+(Complex &c1, Complex &c2)
    {
    	Complex tempc;
    	tempc.real = c1.real + c2.real;
    	tempc.imag = c1.imag + c2.imag;
    	return tempc;
    }
    

从原则上讲,要尽量将重载运算符函数作为成员函数,但还因考虑其他各方因素和习惯,以下方式可供参考
(1)C++规定,赋值运算符“=”、下标运算符“[]”、函数调用运算符“()”、成员运算符“->”、必须作为成员函数重载。
(2)流插人“<<”和流提取运算符“>>”类型转换运算符函数不能定义为类的成员函数,只能作为友元函数。
(3)一般将单目运算符和复合运算符( +=,-=,/=,*=,&=,!=,^=,%=,>>=,<<=)重载为成员函数。
(4)一般将双目运算符重载为友元函数

完整代码(可供参考)

#include <iostream>
using namespace std;
class Complex{
public:
	Complex(){real=0;imag=0;}
	Complex(int, int);
	Complex::operator+(int i);
	friend operator+(int i, Complex &c);
	friend Complex operator+(Complex &c1, Complex &c2);
	void display();
	
private:
	int real;
	int imag;
};

//构造函数 
Complex::Complex(int real, int imag)
{
	this->real = real;
	this->imag = imag;
}

//复数+整数 
Complex Complex::operator+(int i)
{
	Complex tempc;
	tempc.real = real + i;
	tempc.imag = imag;
	return tempc;
}

//整数 +复数 
Complex operator+(int i, Complex &c)
{
	Complex tempc;
	tempc.real = i + c.real;
	tempc.imag = c.imag;
	return tempc;
}
//复数+复数 一般情况下双目运算符重载为友元函数 
Complex operator+(Complex &c1, Complex &c2)
{
	Complex tempc;
	tempc.real = c1.real + c2.real;
	tempc.imag = c1.imag + c2.imag;
	return tempc;
}

void Complex::display()
{
	cout << "(" << real << "," << imag << "i)" << endl;
}

int main()
{
	Complex c1(3,4);
	Complex c2(5,-10);
	Complex c3,c4,c5;
	c3 = c1 + c2; 	//相当于:c3 = c1.operator+(c2); 
	c4 = c1 + 4;
	c5 = 5 + c2;
	 
 	cout << "c1=";		c1.display();
	cout << "c2=";		c2.display();
	cout << "c1+c2=";	c3.display();
	cout << "c1+4=";	c4.display();
	cout << "5+c2=";	c5.display();
	return 0;
} 

重载双目运算符

双目运算符是C++中最常见的运算符,双目运算符有两个操作数,通常在运算符的左右侧,重载函数应该有两个参数,也通常设置为友元函数作为运算符重载函数。
典例:声明一个字符串类String,用来存放不定长的字符串,重载运算符“==”和“>”,用于两个字符串的等于、小于和大于的比较运算。
为了程序的设计了与便于理解,程序设计分步骤编写。
1. 先建立一个String类

#include <iostream>
#include <string.h>

using namespace std;
class String{
public:
	//构造及打印函数 
	String(){p=NULL;}		//无参构造 
	String(char *str){p=str;}	//有参构造 
	void display(){cout << p << endl;}	//打印字符串 	
private:
	char *p;
};

int main()
{
	//测试代码 
	String str1("Hello"),str2("world");
	str1.display();
	str2.display();
	return 0;
} 

2. 重载运算符>
通过全局函数作类友元的方式重载运算符>,其重载函数实现体如下所示。

bool operator>(String &str1, String &str2)
{
	if(strcmp(str1.p,str2.p)>0)
		return true;
	else
		return false; 
}

这只是一个并不很完善的程序,但是,已经完成实质性的工作了,运算符重载成功了。既然对运算符“>”的重载成功了,其他两个运算符的重载如法炮制即可
3. 重载其他运算符

  • 重载运算符“<”

    重载运算符< 
    bool operator<(String &str1, String &str2)
    {
    	if(strcmp(str1.p,str2.p)<0)
    		return true;
    	else
    		return false; 
    }
    
  • 重载运算符“==”

    //重载运算符= 
    bool operator==(String &str1, String &str2)
    {
    	if(strcmp(str1.p,str2.p)==0)
    		return true;
    	else
    		return false; 
    }
    
  • 同时记得将上述三个重载函数声明为类的友元函数

    //运算符重载函数 
    friend bool operator>(String &str1, String &str2);
    friend bool operator<(String &str1, String &str2);	
    friend bool operator==(String &str1, String &str2);	
    
  • 测试代码:

    int main()
    {
    	//测试代码 
    	String str1("Hello"),str2("world");
    	cout << (str1>str2) << endl; 
    	cout << (str1<str2) << endl; 
    	cout << (str1==str2) << endl; 
    	return 0;
    } 
    
  • 测试结果

    0
    1
    0

4. 修饰完善,优化输出

//封装比较函数 优化输出
void compare(String &str1, String &str2)
{
	if((str1 > str2)==1)
	{
		str1.display();	cout << " > ";	str2.display();
	}
	else if ((str1 < str2)==1)
	{
		str1.display(); cout << " < ";	str2.display(); 
	}	
	else
	{
		str1.display(); cout << " = ";	str2.display();
	}	
}

增加了一个compare函数用来对两个字符串进行比较,并输出相应的信息。这样可以减轻主函数的负担,同时使主函数简明易读。
先搭框架、逐步扩充、由简到繁、最后完善。边编程、边调试、边扩充。
完整参考程序:

#include <iostream>
#include <string.h>

using namespace std;
class String{
public:
	//构造及打印函数 
	String(){p=NULL;}			//无参构造 
	String(char *str){p=str;}	//有参构造 
	void display(){cout << p;}	//打印字符串
	 
	//运算符重载函数 
	friend bool operator>(String &str1, String &str2);
	friend bool operator<(String &str1, String &str2);	
	friend bool operator==(String &str1, String &str2);	
	
private:
	char *p;
};

void compare(String &str1, String &str2)
{
	if((str1 > str2)==1)
	{
		str1.display();	cout << " > ";	str2.display();
	}
	else if ((str1 < str2)==1)
	{
		str1.display(); cout << " < ";	str2.display(); 
	}	
	else
	{
		str1.display(); cout << " = ";	str2.display();
	}	
}

int main()
{
	//测试代码 
	String str1("hello"),str2("world");
	compare(str1,str2);
	return 0;
} 


//重载运算符> 
bool operator>(String &str1, String &str2)
{
	if(strcmp(str1.p,str2.p)>0)
		return true;
	else
		return false; 
}

重载运算符< 
bool operator<(String &str1, String &str2)
{
	if(strcmp(str1.p,str2.p)<0)
		return true;
	else
		return false; 
}

//重载运算符= 
bool operator==(String &str1, String &str2)
{
	if(strcmp(str1.p,str2.p)==0)
		return true;
	else
		return false; 
}

重载单目运算符

重载单目运算符与重载双目运算符相似,但由于单目运算符只有一个操作数,因此单目运算符重载函数只有一个参数,如果运算符重载函数作为成员函数,则还可省略此参数。

典例:以自增运算符++为例,设计一个Time类,含数据成员minute(分)和sec(秒),模拟秒表,每次走1秒,满60秒进1分钟,此时秒又从0起算。要求输出分和秒的值。

#include <iostream>
#include <string.h>

using namespace std;
class Time{
public:
	//构造及打印函数 
	Time(){min=0;sec=0;}
	Time(int,int);
	void display();
	
	//运算符重载
	Time operator++();
	
private:
	int min;
	int sec;
};

//构造函数 
Time::Time(int min, int sec)
{
	this->min = min;
	this->sec = sec;
}
//运算符重载 
Time Time::operator++()
{
	sec++;
	if(sec>=60)
	{
		min++;
		sec=0;
	}
	return *this;	
}
//打印时间	
void Time::display()
{
	cout << min << ":" << sec << endl;
}

int main()
{
	int i;
	Time time1(34,12);
	for(i=0;i<61;i++)
	{
		++time1;
		time1.display();
	}
	return 0;
} 

程序对运算符“++”进行了重载,使它能用于Time类对象。
但问题是:“++”和“–”运算符有两种使用方式,前置自增运算符和后置自增运算符,它们的作用是不一样的,在重载时怎样区别这二者呢?
针对“++”和“–”这一特点,C++约定:在自增(自减)运算符重载函数中增加一个int型形参就是后置自增(自减)运算符函数。
在上述程序的基础上增加对后置自增运算符的重载。

  • ++运算符重载后置 重载函数
    //运算符重载 ++ 后置 
    Time Time::operator++(int)
    {
    	//建立临时对象 temp 并读取当前值 
    	Time temp(*this);	
    	sec++;
    	if(sec>=60)
    	{
    		min++;
    		sec=0;
    	}
    	return temp;	
    }
    
  • 主函数程序程序
    int main()
    {
    	int i;
    	Time time1(34,12);
    	Time time2;
    	time2=time1++;
    	cout << "time2=tim1++: time1=";	
    	time1.display();	cout << "  time2=";	time2.display();
    	return 0;
    } 
    

重载后置自增运算符时,多了一个int型的参数,增加这个参数只是为了与前置自增运算符重载函数有所区别,此外没有任何作用。在定义函数时也不必使用此参数因此可省写参数名,只须在括号中写int 即可。

重载流插入运算符和"<<“和流提取运算符”>>"

如果想用输出和输入自已声明的类型的数据,必须对它们重载
对"<<“和”>>"重载的函数形式如下:
ostream & operator<<(ostream &, 自定义类 &)
istream & operator>>(istream &, 自定义类 &)
重载“>>”和“<<”的函数只能作为友元函数,不能将他们定义为成员函数

重载流插入运算符和"<<"

典例:在上述代码的基础上,重载输出运算符“<<”输出复数

#include <iostream>
#include <string.h>

using namespace std;
class Complex{
public:
	//构造及打印函数 
	Complex(){real=0;imag=0;}					//无参构造 
	Complex(double i,double j){real=i;imag=j;}	//有参构造 
	Complex operator+(Complex &);				//+号运算符重载 
	friend ostream &operator<<(ostream &output, Complex &c);	//重载cout
	
private:
	double real;
	double imag;
};

Complex Complex::operator+(Complex &c)
{
	Complex temp;
	temp.real = real + c.real;
	temp.imag = imag + c.imag;
	return temp;
} 

ostream &operator<<(ostream &output, Complex &c)
{
	output << "(" << c.real << "," << c.imag << "i)";
	return output;
}

int main()
{
	//测试代码 
	Complex c1(1.2, 2.3);
	Complex c2(0.8, 2.7);
	Complex c3;
	c3 = c1 + c2;
	cout << c1 << "+" << c2 << "=" << c3;
	return 0;
}

程序中重载了运算符“<<”运算符重载函数“operator<<”中的形参output是ostream类对象的引用,形参名output是用户任意起的。
  运算符“<<”的左面是cout,前面已提到cout是在头文件iostream中声明的ostream类对象。“<<”的右面是c3,它是Complex类对象。由于已将运算符“<<”的重载函数声明为Complex类的友元函数编译系统把cout<<c3解释为:
  operator<<(cout, c1)
即以cout和c1作为实参调用下面的“operator<<”函数:

ostream &operator<<(ostream &output, Complex &c)
{
	output << "(" << c.real << "+" << c.imag << "i)";
	return output;
}

调用函数时,形参output成为实参cout的引用,形参c成为c1的引用。因此调用函数的过程相当于执行

cout<< "(" << c1.real << "," << c1.imag << "i)";

return output的作用:
  连续向输出流插入信息,output是ostream类的对象的引用,因此return output就是return cout.

流提取运算符">>"

  • >>运算符重载函数
    istream &operator>>(istream &input, Complex &c) 
    {
    	input >> c.real >> c.imag;
    	return input;
    }
    
    函数的返回值仍然为输入流的引用,第一个参数为输入流的引用,第二个参数为复数的引用,当调用以下函数时,第一个参数被赋值为cin的引用,第二个参数被赋值为c1的引用,程序就相当于执行cin >> c1.real >> c1.imag,执行完毕后返回istream的引用,使得能够继续连续输入c2.
  • 函数的调用
    cin >> c1 >> c2;	//其中c1,c2代表2个复数
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会编程的小江江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值