C++ 面向对象- -运算符的重载(一)

 

运算符重载的方法

运算符重载的方法就是定义一个重载运算符的函数,使指定的运算符不仅能实现原有的功能,还能实现在函数中指定的新加的功能。在使用被重载的运算符时,系统就会自动调用该函数,以实现相应的功能,也就是说,运算符的重载是通过定义函数实现的运算符的重载实质上就是函数的重载

重载运算符的函数一般形式: 函数类型 operator 运算符名称(形参表){ 对运算符的重载处理 } ; 例如重载 “+” 来实现两个复数相加的运算,那么函数可以是: Complex operator + ( Complex a , Complex b) ; 在其格式中, operator 是关键字,是专门用于定义重载运算符的函数, 运算符名称就是 C++中已有的运算符 。函数名是由 operator 和运算符 组成的,上面的 “operator +” 就是函数名,意思是对运算符+ 重载的函数 。可以说是函数 “operator +” 重载了运算符 “+” ,在程序中执行两个复数相加时就自动调用该重载函数。

下面是一个对 “+” 重载以实现两个复数相加的例子:

#include <iostream>
using namespace std;
class Complex{
		double real;
		double imag;
	public:
		Complex(double r=0,double i=0):real(r),imag(i){}
		void display(){
			cout<<"("<<real<<","<<imag << "i)" <<endl;
		}
        //Complex complex_add(Complex a);
		Complex operator+(Complex a);
};
/*Complex Complex::complex_add(Complex a){
    Complex b;
	b.real=real+a.real ;
	b.imag=imag+a.imag ;
	return b;
}*/
Complex Complex::operator+(Complex a){
	Complex b;
	b.real=real+a.real ;
	b.imag=imag+a.imag ;
	return b;
}
int main(){
    Complex c1(1,1);
	cout<<"c1=";c1.display();
    Complex c2(2,2);
	cout<<"c2=";c2.display();
	Complex c3;
    c3=c1+c2;
	cout<<"c1+c2=";c3.display();
}

上边的程序中有对运算符 “+” 的重载实现两个复数相加,也有通过调用函数来实现复数相加,其结果都是一样的。在上边的例子中,运算符 “+” 被重载过,系统在编译时将程序中的表达式 c1+c2 解释为 c1.operator+ (c2) ,前边也已提过,“operator+”是一个函数名,所以这也算是通过函数调用来实现的,只是这个运算符重载函数是系统自动调用执行。

上边的运算符重载函数还可以简写:

Complex Complex::complex_add(Complex a){
	return Complex(real+a.real,imag+a.imag) ;
}

Complex 用来建立一个临时对象,它没有对象名,是一个无名对象,return 语句将此临时对象作为函数返回值。

另外可以试试实现一个整数和一个复数的相加,然后把它们互换一下位置再试试;函数的位置改变试试,作为成员函数、友元函数、普通函数。

重载运算符的规则

在运算符重载时一定要遵守这几个规则:

  • 系统不允许用户自己定义新的运算符,只能对C++已有的运算符进行重载。
  • C++中允许重载的运算符:
双目算术运算符 +(加)、-(减)、*(乘)、/(除)、%(取模)
关系运算符 ==(等于)、!=(不等于)、<(小于)、>(大于)、<=(小于等于)、>=(大于等于)
逻辑运算符 || (逻辑或)、&&(逻辑与)、!(逻辑非)
单目运算符 +(正)、-(负)、*(指针)、&(取地址)
自增自减运算符 ++(自增)、--(自减)
位运算符 |(按位或)、&(按位与)、~(按位取反)、^(按位异或)、<<(左移)、>>(右移)
赋值运算符 =、+=、-=、/=、%=、|=、^=、<<=、>>=
空间申请与释放 new、delete、new[]、delete[]
其他运算符 ()(函数调用)、->(成员访问)、->*(成员指针访问)、,(逗号)、[](下标)

不允许重载的运算符只有 5 个:. (成员访问运算符)、*(成员指针访问运算符)、::(域运算符)、sizeof(长度运算符)、?:(条件运算符)。前两个是为了保证访问成员的功能不能被改变,域运算符和sizeof运算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征。

这里基本上把运算符都包含了进来,但有很多基本上都不怎么用,了解一下就好。

  • 重载不能改变运算符运算对象(即操作数)的个数。
  • 重载不能改变运算符的优先级别,如果希望改变某运算符的优先级,只能用加圆括号的方法强制改变重载运算符的运算顺序。
  • 重载不能改变运算符的结合性,如赋值运算符“=” 是右结合性(从右向左)。
  • 重载运算符的函数不能有默认的参数,否则就改变了运算符参数的个数。
  • 重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个类对象(或类对象的引用),也就是说参数不能全部是C++中的标准类型,防止用户修改用于标准类型数据的运算符的性质。
  • 用于类对象的运算符一般必须重载,但有两个例外,运算符“=”和 “&” 不用重载。
  • 从理论上说,可以将一个运算符重载为执行任意的操作,但应当使重载运算符的功能类似于标准类型数据时所实现的功能。如
int operator+(int a,int b){
	return (a-b) ;
}

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

对运算符重载的函数有两种处理方式:1)把运算符重载的函数作为类的成员函数;2)运算符重载的函数不是类的成员函数(可以是一个普通函数),在类中把它声明为友元函数。

如前边写的两个复数相加的例子,就是把运算符重载作为类的成员函数,其有一个参数是隐含的,运算符函数用 this 指针隐式地访问类对象的成员,因此重载函数中只需要一个形参即可。

对友元运算符重载函数举一个例子:

#include <iostream>
using namespace std;
class Complex{
		double real;
		double imag;
	public:
		Complex(double r=0,double i=0):real(r),imag(i){}
		void display(){
			cout<<"("<<real<<","<<imag << "i)" <<endl;
		}
		friend Complex operator+(Complex a,Complex b);		//重载函数作为友元函数 
};

Complex operator+(Complex a,Complex b){		//注意和之前不一样的还有 友元函数不需要域运算符 “::” 。 
	Complex c;
	c.real=b.real+a.real ;
	c.imag=b.imag+a.imag ;
	return c;
}
int main(){
    Complex c1(1,1);
    cout<<"c1=";
    c1.display();
    Complex c2(2,2);
    cout<<"c2=";
    c2.display();
    Complex c3;
    c3=c1+c2;
    c3.display();
}

重载运算符函数作为友元函数和成员函数区别不大,怎么用都行,但需要知道的是,如果将运算符重载函数作为成员函数,它可以通过 this 指针自由地访问奔类中的数据成员,因此可以少写一个函数的参数,但必须要求运算表达式(如 c1+c2)中的第一个参数(即运算符左边的操作数)是一个类对象,而且与运算符函数的类型相同,因为必须通过类的对象去调用该类的成员函数,而且只有运算符重载函数返回值与该对象同类型,运算结果才有意义。像前面提到过的问题,如果使一个整数和一个复数相加该怎么写,如果将运算符重载函数作为成员函数只能(c1+ int ),它们两个的顺序是不可改变的;将双目运算符重载为友元函数时,由于函数不是该类的成员函数,因此在函数的形参数表列中必须有两个参数,不能省略,顺序任意,实参和形参的类型对应就行(如果想在主函数中同时实行 c2=c1+i 和 c2=i+c1 这两个部分,那么需要对这个友元重载函数重载两次,第二次将形参的顺序互换一下,那么在编译的时候,系统会根据表达式额形式选择调用与之匹配的运算符重载函数)。

注意:由于友元的使用会破坏类的封装,因此从原则上说,尽量将运算符函数作为成员函数。但后面的流插入和流提取运算符、类型转换运算符都不能定义为类的成员函数,只能是作为友元函数。一般将单目运算符和复合运算符(+=、-=、/=、*=、&=、!=、%=、`=、<<=、>>=)重载为成员函数,一般将双目运算符重载为友元函数。

 


猜你喜欢

转载自blog.csdn.net/qq_43305922/article/details/85457062