博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

 接下来本节将介绍另外一个重要的重载:运算符重载。学习到现在,像+*这样的运算符只能用于预定义的数据类型,原因很简单:编译器认为所有常见的运算符都是用于这些数据类型的,例如,它知道如何把两个long加起来,或者如何从一个double中减去另一个double,并生成合适的中间语言代码。但在定义自己的类或结构时,必须告诉编译器:什么方法可以调用,每个实例存储了什么字段等所有的信息。同样,如果要在自己的类上使用运算符,就必须告诉编译器相关的运算符在这个类中的含义。此时就要定义运算符重载。

       小天:能够用通俗点的语言描述下运算符的概念不?还有只有算术运算符可以重载吗?

老田:通俗的说,运算符重载就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。其实将两个string类型相加这个运算符就重载过的。所以加号在面对数值类型的时候就是求和的作用。而面对两个string类型的时候就是连接字符串的作用。例如

            int x = 5, y = 10;

            int z = x + 5;

 

            string str1 = "", str2 = "";

            string str3 = str1 + str2;

 

而运算符重载不仅仅限于算术运算符。还需要考虑比较运算符 ==<>!=>=<=。例如,语句if(a==b)。对于类,这个语句在默认状态下会比较引用ab,检测这两个引用是否指向内存中的同一个地址,而不是检测两个实例是否包含相同的数据。对于string类,这种操作就会重写,比较字符串实际上就是比较每个字符串的内容。可以对自己的类进行这样的操作。对于结构,==运算符在默认状态下不做任何工作。试图比较两个结构,看看它们是否相等,就会产生一个编译错误,除非显式重载了==,告诉编译器如何进行比较。

在许多情况下,重载运算符允许生成可读性更高、更直观的代码,包括:

l  在数学领域中,几乎包括所有的数学对象:坐标、矢量、矩阵、张量和函数等。如果编写一个程序执行某些数学或物理建模,肯定会用类表示这些对象。

l  图形程序在计算屏幕上的位置时,也使用数学或相关的坐标对象。

l  表示大量金钱的类(例如,在财务程序中)

l  字处理或文本分析程序也有表示语句、子句等的类,可以使用运算符把语句连接在一起(这是字符串连接的一种比较复杂的版本)

下表展示了所有可以重载和不可以重载的运算符:

可被重载的

一元运算符

+, -, !, ~, ++, --, true, false

注意:truefalse运算符必须成对重载

二元运算符

+, -, *, /, %, &, |, ^, <<, >>

关系运算符

==, !=, <, >, <=, >=

注意:必须成对重载

不可被重载的

条件运算符

&&, ||

数组运算符

[],但可以定义索引器。

转换运算符

(),但可以定义隐式类型转换和显式类型转换运算符。

赋值运算符

+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=,但重载相关的二元运算符,它们也就具备了同样的新功能

其他运算符

=, ., ?:, ->, new, is, sizeof, typeof

C#要求成对重载比较运算符。如果重载了==,也必须重载!=,否则会产生编译错误。另外,比较运算符必须返回bool类型的值。这是它们与算术运算符的根本区别。两个数相加或相减的结果,理论上取决于数的类型。而两个Vector的相乘会得到一个标量。另一个例子是.NET基类System.DateTime,两个DateTime实例相减,得到的结果不是DateTime,而是一个System.TimeSpan实例,但比较运算得到的如果不是bool类型的值,就没有任何意义。

另外,有许多类与运算符重载并不相关。不恰当地使用运算符重载,会使使用类型的代码很难理解。例如,把两个DateTime对象相乘,在概念上没有任何意义。

本文章为天轰穿原创作品,转载请注明出处及作者。