C++运算符重载相关问题

 

目录

 

0.什么是运算符重载

C++运算符重载:

1. C++运算符重载的原则是什么?有哪些规则?

C++运算符重载:

重载原则:

重载规则:

2. C++能/不能重载的运算符有哪几个?

能重载的运算符有:

不能重载的运算符有:

3. C++运算符重载的形式有哪几种?

普通函数:

友元函数:

成员函数:

4.C++几种特殊的运算符重载


0.什么是运算符重载

运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

引用wikipedia对运算符重载的解释:

运算符重载

在计算机程序设计中,运算符重载(英语:operator overloading)是多态的一种。这里,运算符(比如+,=或==)被当作多态函数,他们的行为随着其参数类型的不同而不同。运算符并不一定总是符号。

运算符重载通常只是一种语法糖。它可以简单地通过函数调用来模拟:

a + b * c

在一个支持运算符重载的语言里,上面的写法要比下面的写法有效而简练:

add(a, multiply(b, c))

(假设运算符* 的优先级高于运算符 +)

当一种语言允许运算符在某种情况下被隐式调用的时候,运算符重载将不只提供写法上的方便。例如,Ruby中的to_s运算符就是如此,它返回一个对象的字符串表示。

用途

运算符重载由于使程序员能够根据运算符类型的不同来决定运算符功能的不同而有多样用途。C++中<<的使用就是一个例子。表达式

a << 1

当a是整型变量时将返回a的两倍,但是当a是一个输出流时将向这个流中写入“1”。因为运算符重载允许程序员改变运算符通常的语义,慎重使用运算符重载通常被认为是一个好习惯。

C++运算符重载:

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

首先来看一个问题:代码定义了一个复数类complex,然后用complex定义了2个复数,如何实现这2个复数的加法呢?这个问题的解决就需要用到运算符重载的知识。

//运算符重载的必要性
#include 
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;
}

1. C++运算符重载的原则是什么?有哪些规则?

C++运算符重载:

p系统本身就提供了很多个重载版本,如:

int operator + (int,int);

double operator + (double,double);

重载原则:

  • 1)重载操作符必须具有一个类类型或者是枚举类型的操作数。
    • int operator+(int, int);//不能重载
  • 2)重载操作符必须具有一个类类型或者是枚举类型的操作数
    • 操作符的优先级、结合性或操作数个数不能改变

  • 3)p不再具备短路求值特性
    • 重载操作符并不保证操作数的求值顺序  &&  ||   
  • 4)不能臆造并重载一个不存在的运算符
    • 如@, #,$等

重载规则:

  • 1)除了类属关系运算符 " . " 、成员指针运算符 " .* " 、作用域运算符 " :: " 、sizeof运算符和三目运算符 " ?: " 以外,C ++ 中的所有运算符都可以重载。
  • 2)重载运算符限制在C ++ 语言中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符。
  • 3) 运算符重载实质上是函数重载,因此编译程序对运算符重载的选择,遵循函数重载的选择原则。
  • 4 )重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构。
  • 5 )运算符重载不能改变该运算符用于内部类型对象的含义。它只能和用户自定义类型的对象一起使用,或者用于用户自定义类型的对象和内部类型的对象混合使用时。
  • 6 )运算符重载是针对新类型数据的实际需要对原有运算符进行的适当的改造,重载的功能应当与原有功能相类似,避免没有目的地使用重载运算符

2. C++能/不能重载的运算符有哪几个?

能重载的运算符有:

双目算术运算符 + (加),-(减),*(乘),/(除),% (取模)
关系运算符 ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
逻辑运算符 ||(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符 + (正),-(负),*(指针),&(取地址)
自增自减运算符 ++(自增),--(自减)
位运算符 | (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符 =, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放 new, delete, new[ ] , delete[]
其他运算符 ()(函数调用),->(成员访问),,(逗号),[](下标)

不能重载的运算符有:

  成员访问符 .

  成员指针访问运算符 .*

  域运算符 ::

  长度运算符 sizeof 

  条件运算符号 ?:

 

3. C++运算符重载的形式有哪几种?

                   1)采用普通函数的重载形式

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

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

普通函数:

普通函数形式重载运算符,要求待操作的属性必须是public类型的。

// 普通函数形式 的 运算符重载
#include 
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;
}

友元函数:

用成员函数重载双目运算符时,左操作数无须用参数输入,而是通过隐含的this指针传入,这种做法的效率比较高

此外,操作符还可重载为友元函数形式,这将没有隐含的参数this指针。对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。

p重载为友元函数的运算符重载函数的声明格式为:

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

以友元函数形式重写代码:

//友员函数形式 的 运算符重载
#include 
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;
}

成员函数:

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

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

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

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

{

//成员函数形式 的 运算符重载
#include 
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;
}

4.C++几种特殊的运算符重载

(有待补充...)

 

 

你可能感兴趣的:(C++学习,C++,运算符重载,C++重载)