第9章运算符重载C#允许用户根据所创建的类来定义运算符的含义,该过程称为运算符重载。通过重载运算符,可以扩展运算符在类中的作用。运算符重载的优点是:它允许将新的类类型无缝隙地整合进用户自己的编程环境中,这种类型扩展是面向对象语言包括C#的一种重要功能。本章将详细讲解运算符重载的使用。9.1什么是运算符重载运算符重载是根据用户所创建的类来定义运算符的含义。这样运算符的作用完全由用户决定,同时类和类之间的运算符含义可以不同。换句话说,通过运算符的重载改变了运算符运算的规则,可以扩展运算符在类中的作用。通常情况下,运算符只允许数与数、数与数据和数据与数据之间的运算。通过运算符的重载,不同类型的对象都可以进行运算。如下图所示,在教师类Teacher中,通过教师级别的增加,其相应属性也会改变。一般的运算符不能满足这种运算,所以就必须重新定义运算符的规则,这样就产生了运算符的重载。它能让我们更方便的使用不同的运算符。助教级别:1工资:1000奖金:500补助:500++讲师级别:2工资:1500奖金:700补助:1000副教授级别:3工资:2000奖金:1000补助:1500教授级别:4工资:3000奖金:2000补助:2000++++教师类Teacher9.2如何重载运算符运算符重载是一个特殊的方法。其语法形式如下图所示。其中,运算符重载方法的访问修饰符必须是public;该方法必须是静态方法;public和static满足一个,就可以了;operator是运算符重载的关键字;op表示要重载的运算符;参数列表表示调用该方法所要传递的参数。publicstatictypeoperatorop(type参数列表){………………}规定修饰符返回值数据类型运算符关键字规定参数列表【示例9-1】以下代码演示对Team类实现加号运算符的重载。publicstatic是修饰符。Team表示运算的结果类型。operator是运算符重载的关键字。oper1和oper2是Team类类型的两个参数。注意:该参数类型必须是对象或者结构。如果不是,会提示如下错误信息:运算符的参数必须是包含类型。publicstaticTeamoperator+(Teamoper1,Teamoper2){//方法代码暂时省略}修饰符类名关键字运算符Team类下的两个参数对列9.2.1一元运算符重载一元运算符只有一个操作数。常见的一元运算符包括非运算(-)、自增运算符(++)和自减运算符(--)。一元运算符重载语法如下图所示。【示例9-2】定义了一个银行账号类Program。通过将非运算符(-)重载,实现将银行账号金额清空的功能。其中,参数必须是对象或者结构类型,否则会提示错误信息:一元运算符的参数必须是包含类型。【示例9-3】定义了一个银行卡类Program。通过自增运算符重载,实现银行卡升级的功能。【示例9-4】定义了一个人年龄的类Program。通过自减运算符重载,实现这个公司的级别的查看。重载自增与自减运算符,只需要返回自增或自减的值,但不改变主调对象。其中,应特别主意前缀和后缀的区别。9.2.2二元运算符重载二元运算符的重载与一元运算符的重载类似。常见的二元运算符有加法(+)、减法(—)。二元运算符重载格式如下图所示。【示例9-5】介绍通过定义类Program。利用重载二元运算符加法(+)运算将整型值加到Program类型对象的各个坐标上,实现坐标轴的平移。示例9-5中将运算符“+”重载,给原本的“+”赋予另一层含义,即将各个x轴、y轴、z轴都相加。实现了坐标轴的平移。publicstatictypeoperatorop(typeoper,typeoper2){………………}运算符参数9.3关系运算符重载关系运算符,如“==”或“”,也可以重载。重载关系运算符返回true或false值。重载后的关系运算符可以用于条件表达式。关系运算符重载必须对他们成对重载。例如,如果重载==运算符,那么就必须重载!=运算符。成对重载的运算符有:“==”和“!=”、“”和“”、“=”和“=”。关系运算符重载格式如下图所示。publicstaticbooloperator(Programop1,Programop2){//returntrue/false;}publicstaticbooloperator(Programop1,Programop2){//returntrue/false;}运算符返回数据类型【示例9-6】利用重载“”和“”,判断三个对象的大小,输出最大对象。在该例中,返回数据类型必须是bool,否则会提示错误。错误信息如下:无法将类型”bool”隐式转换为”重载关系运算符.Program”而且,如果重载“”运算符,那么也必须重载“”运算符,否则编译器会报错。错误信息如下:运算符”重载关系运算符.Program.operator(重载关系运算符.Program,重载关系运算符.Program)”要求也要定义匹配的运算符””9.4重载TRUE和FALSE关键字true和false也能够作为一元运算符进行重载。一旦给一个类实现了true和false的重载,用户就能够使用该类的对象控制if、while、for和do..while语句,或者在问号表达式中使用它们。通用格式如下图所示。其中,true和false运算符必须成对重载,不能只重载其中一个。两个方法的返回值都是bool类型。publicstaticbooloperatortrue(Typeop){//returntrueorfalse}publicstaticbooloperatorfalse(Typeop){//returntrueorfalse}返回该对象true或false【示例9-7】演示如何在Program类中实现true和false的重载。只要至少有一个坐标不为0,那么Program对象就为真。如果所有坐标都是0,那么对象为假。注意:(1)true和false可以作为两个操作符被重载,并且如果重载true那么必然需要重载false,否则编译器会报错。错误信息如下:运算符”重载true和false.Program.operatortrue(重载true和false.Program)”要求也要定义匹配的运算符”false”(2)当使用&&操作符时首先调用false操作符先判定是否为假,当使用||操作符的时候首先调用true操作符先判定是否为真。9.5逻辑运算符重载逻辑运算符:“&”、“|”、“!”、“&&”和“||”。通常,可以重载的运算符有“&”、“|”和“!”。但是通过遵循一些规则,我们仍然能够利用“&&”和“||”短路运算符简化运算的优点。9.5.1逻辑运算符重载的简单方式重载“&”和“|”运算符,其返回bool类型的结果。重载“!”运算符通常也返回bool类型的值。逻辑运算符重载格式如下图所示。【示例9-8】为Program类型的对象重载“!”、“&”和“|”逻辑运算符。与前面的示例一样,只要至少一个坐标不为0,就认为Program对象为真。如果3个坐标都为0,那么该对象为假。publicstaticbooloperatorop(Programop1,Programop2){//returntrue/false;}运算符返回数据类型9.5.2使用短路运算符如果要使用“&&”和“||”这两个短路运算符,那么就必须遵循下面4个规则。类必须重载“&”和“|”运算符。重载的“&”和“|”运算符方法的返回类型必须是重载运算符的类的类型。每个参数必须是对重载运算符的类对象的引用。必须为该类重载true和false运算符。当这些条件都满足时,短路运算符就自动变为可用【示例9-9】实现了Program类中“&”、“|”和“!”运算符的重载,以使短路运算符“&&”和“||”可用。9.6转换运算符转换运算符允许将类的对象转换成另一种类型。转换运算符有助于将类类型完整地集成到C#的编程环境中,因为它允许类的对象自由地和其他类型的数据混合使用,只要定义了这些类型的相应转换即可。转换运算符有两种形式:隐式和显式。其通用形式如下图所示。其中,public和static是规定的修饰符。implicit是隐式转换的关键字。explicit是显式转换的关键字。target-type为转换的目标类型,source-type是转换的源类型。value是转换后类对象的值。publicstaticimplicit/explicitoperatortarget-type(soure-typev){//returnvalue;}规定的修饰符隐式/显式关键字转换的目标类型转换的源类型转换后类对象的值重载关键字【示例9-10】以下代码演示Program类型的隐式转换。隐式的指定转换运算符会自动调用转换过程。显式的指定转换运算符,将在使用强制类型转换时调用转换过程。对于相同目标类型和源类型的转换,不能同时定义隐式转换运算符和显式转换运算符。publicstaticimplicitoperatorint(Programop){returnop.x+op.y+op.z;}规定修饰符隐式转换关键字转换的目标类型重载关键字返回值源类型【示例9-11】将Program类型的对象转换成整数类型,来实现三维坐标的相加。【示例9-12】将前面的程序修改为使对象显式的转换为int类型。其中,因为转换运算符是显式的,所以必须显式地强制执行int类型的转换。例如,在下面的语句中:i=(int)a;如果去除强制类型转换,程序编译将报错。错误信息如下:无法将类型”显式转换.Program”隐式转换为”int”。存在一个显式转换(是否缺少强制转换?)对于转换运算符,有如下的限制条件。转换的目标类型或源类型必须是在其中声明转换的类。例如,不能重新定义从double类转到int类型的准换不能定义以object对象作为目标类型或源类型的转换;对同一个源类型和目标类型的转换,不能同时定义它的显式和隐式转换;不能定义从基类到派生类的转换;不能定义从接口到其他类型或从其他类型到接口的转换。9.7注意问题重载运算符是也有一些限制。首先,不能改变任何运算符的优先级。其次虽然运算符方法可以选择忽略操作数,但不能修改运算符所要求的操作数量。另外有一些运算符不能重载。9.7.1重载后运算符的优先级运算符重载后也是有优先级的,下表将展示C#中运算符重载后的优先级:一般来说,不使用优先级来获取计算结果,采取括号()来制定运算符的运算顺序,可以是代码更整洁,避免潜在的错误。优先级类别运算符1基本(x)x.yf(x)a[x]x++x--newtypeofsizeofcheckedunchecked2单目+-!~++x--x(T)x3乘法与除法*/%4加法与减法=-5移位运算≤≥6关系运算﹤==is7条件等==!=8位逻辑与&9位逻辑异或^10位逻辑或|11条件与&&12条件或‖13条件?:14赋值=*=/=%=+=-===&=^=|=【示例9-13】演示了重载后运算符的优先级。在该例中,程序在运行时首先重载“*”,运行结果为1;其次重载“+”,运行结果2;最后运行表达式,输出结果。9.7.2不能重载的运算符运算符,可以分为一元、二元和三元运算符,在它们中有一些可以重载,但还有一些并不能,不可以重载的运算符包括:赋值运算符和复合赋值运算符(=、=+、/=和%=等)条件运算符(&&、||和三元运算符?:)句点运算符(.)调用运算符(())checked和unchecked运算符new运算符typeof运算符as和is运算符数组运算符([])9.8小结本章主要介绍了运算符的重载,其中包括一元运算符重载、二元运算符重载、关系运算符重载、true和false重载和逻辑运算符重载,以及运算符转换。其中重点是一元和二元运算符重载,