C#运算符重载的一些总结

开发 后端
C#运算符重载的概念,种类,C#运算符重载应用,本文向你系统的讲解了C#运算符重载的一系列问题。希望对你学习C#运算符重载有所帮助。

C#运算符重载的概念是什么呢?

重载是面向对象中的一个重要概念,它是对象多态性的一种不完全体现,人们通常所说的重载,往往指的是函数的重载。本文向读者介绍一种新的重载模型——运算符重载。

为什么需要C#运算符重载

函数的重载为一个对象上的相同行为提供不同的参数方式,这样,开发人员便可以使用这些不同的参数实现类似的功能。一组函数重载决策一般实现的功能是相同的,例如对 Object 对象上的 ToString() 方法就有几个重载版本,虽然它们接受的参数不同,但却都表达同一个行为的最终结果。参数的不同导致函数重载版本的签名不同,这样编译器很容易知道需要调用那一个重载版本。这种技术给开发人员带来了方便。

现在我们试图对重载的定义进行推广。先让我们看看最简单的例子,我们通常需要像这样声明并初始化一个值类型的变量:

  1. int digit = 5;  
  2. string sayHello = "Hello, World"

这里的“=”运算符,就是将右边的值传递给左边变量的赋值运算符。这里,5 的类型为 int,“Hello, World”的类型为 string,这与左边被赋值的变量类型完全一致。

但对于上述的解释,我们还可以这样认为:5 的类型为 uint 或 byte,"Hello, World"的类型为 char[],那么如此一来,赋值运算左边和右边的类型就不在等同,那么编译器如何处理呢?有人会说,这就是“隐式类型转换”,这个答案确实很好,但隐式类型转换的规则已经被编译器确定,如果赋值运算的两端不遵循隐式类型转换规则,则需要显式类型转换,例如:

  1. char c = '2';  
  2. string s = (string)c;  
  3. int i = (int)c; 

这些显式类型转换并不适用于任何场合,也许人们希望在其自定义的类中也能用赋值、加减乘除等语法操作它们。

对象和对象之间是可能存在这种特殊的运算关系的,一个典型的例子就是“复数”对象。复数是一个值类型对象,它包含两个 double 类型的域,两个复数对象可以被加、减、乘、除和相等性判断,但无法比较大小。我们试想可以如此操作复数类:

  1. Complex c1, c2;  
  2. c1 = new Complex(3, 4);  
  3. c2 = "4+5i";  
  4. var c3 = c1 * c2 / -c1 + c2;  
  5. if (c1 == c2) c3 = c1; else c3 = c2; 

我们可以从这些代码可以预见C#运算符重载所需要实现的功能:

1、支持隐式类型转换和显式类型转换的重载决策。

2、支持基本二元运算符,如加、减、乘、除等。

3、支持基本一元运算符,如取负、取反、自增、自减等。

4、支持基本关系运算符,如大于、小于、等于和不等于等。

5、实现更加复杂的运算符,如三元运算、[]、()、位运算等。

事实上,运算符重载的提出就是为了解决这些问题。在 CLR 框架下的各种 CLR 语言,均不同程度的支持运算符重载。Visual Basic 在 8.0 版本上(也就是 Visual Studio 2005)也支持了运算符重载,运算符重载除了以上列出的优点外,还具备如下特点。

1、使得代码更加容易理解和阅读。

2、可以利用现有运算符的优先级关系规则处理对象之间的运算。

3、使得代码更加灵活,对象可操作性更好。

4、开发人员可以举一反三,因为他们熟悉了常规值类型上的运算符使用,这样可以直接将这些规则引入到自定义对象上。

下面我们通过介绍复数类的定义,来深入 C# 语言中的运算符重载。

C# 运算符重载决策示例

下面的例子定义一个 Complex 类,实现了复数加、减、乘和除的四则运算。C# 中定义常规运算符的语法如下:

  1. [public | private | protected | internal | internal protected]   
  2.  
  3. static <return type> | implicit | explicit operator  (  ) 

下面是C#运算符重载(C# 3.0) 代码。

  1.     struct Complex  
  2.     ...{  
  3.         public double Real ...{ getset; }  
  4.         public double Imaginary ...{ getset; }  
  5.  
  6.         public Complex(double real, double imaginary) : this() ...{ 
  7. this.Real = real; this.Imaginary = imaginary; }  
  8.  
  9.         public static Complex operator +(Complex c1, Complex c2)  
  10.         ...{  
  11.             return new Complex ...{ Real = c1.Real + c2.Real, 
  12. Imaginary = c1.Imaginary + c2.Imaginary };  
  13.         }  
  14.  
  15.         public static Complex operator -(Complex c1, Complex c2)  
  16.         ...{  
  17.             return new Complex ...{ Real = c1.Real - c2.Real, 
  18. Imaginary = c1.Imaginary - c2.Imaginary };  
  19.         }  
  20.  
  21.         public static Complex operator *(Complex c1, Complex c2)  
  22.         ...{  
  23.             return new Complex ...{ Real = c1.Real * c2.Real - c1.Imaginary * c2.Imaginary, 
  24. Imaginary = c1.Real * c2.Imaginary   - c1.Imaginary * c2.Real };  
  25.         }  
  26.  
  27.         public static Complex operator /(Complex c1, Complex c2)  
  28.         ...{  
  29.             return new Complex ...{ Real = -c1.Real * c2.Real + c1.Imaginary * c2.Imaginary,
  30.   Imaginary = -c1.Real *   c2.Imaginary + c1.Imaginary * c2.Real };  
  31.         }  
  32.     } 

由于C#运算符重载定义在定义它的对象实例上生效,所以可以改写 operator - 和 operator / 运算,使其更加简单。

  1. public static Complex operator -(Complex c1, Complex c2)  
  2. ...{  
  3.     return c1 + new Complex ...{ Real = c2.Real, Imaginary = c2.Imaginary };  
  4. }  
  5.  
  6. public static Complex operator /(Complex c1, Complex c2)  
  7. ...{  
  8.     return c1 * new Complex ...{ Real = -c2.Real, Imaginary = -c2.Imaginary };  

这样我们就可以很方便的使用 Complex 类:

  1. var c1 = new Complex(3, 4), c2 = new Complex(1, 2);  
  2. var c3 = c1 * c2;  
  3. Complex c4 = c1 - c2 / c3 + c1; 

为了实现更加简单的赋值,我们还需要实现隐式类型转换(从 string 到 Complex)。

  1. public static implicit operator Complex(string value)  
  2. ...{  
  3.     value = value.TrimEnd('i');  
  4.     string[] digits = value.Split('+''-');  
  5.     return new Complex ...{ Real = Convert.ToDouble(digits[0]), 
  6. Imaginary = Convert.ToDouble(digits[1]) };  

可以通过如下代码对实例进行赋值。

  1. Complex c = "4+5i"

在编译器生成这些运算符重载代码时,实际上会为每个已被重载运算符定义一个特殊名称的方法。如 operator +,其实等同于如下代码:

  1. [SpecialName]  
  2. public static Complex op_Addition(Complex c1, Complex c2)  
  3. ...{  
  4.     return new Complex ...{ Real = c1.Real + c2.Real, 
  5. Imaginary = c1.Imaginary + c2.Imaginary };  

C# 运算符重载一览表

您可以在 C# 中对于以下运算符进行重载决策。

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

这些一元运算符可被重载。

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

这些二元运算符可被重载。

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

这些关系运算符可被重载。

◆&&, ||

这些条件运算符不能被重载,但它们的值被 & 和 | 评估,而这两个运算符可以重载。

◆[]

数组运算符不能被重载,但您可以定义索引器。

◆()

转换运算符不能被重载,但您可以定义隐式类型转换和显式类型转换运算符。

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

这些赋值运算符不能被重载,但他们的值,如 +=,会被 + 评估,而 + 可以被重载。

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

这些运算符不能被重载。

C# 中的运算符重载结论

C# 中的运算符重载是对重载概念的一个重要补充和发展,它针对对象关系中的多元关系和四则运算、关系运算等常规运算提供了重载支持,开发人员可以利用运算符重载优化利用到这些关系的实现代码中,以提高生产力。

【编辑推荐】

  1. C#运算符重载实例浅析
  2. C#运算符重载概念及应用详解
  3. C#运算符重载实现复数运算
  4. C#运算符重载实例解析
  5. C#运算符重载的一些总结
责任编辑:仲衡 来源: CSDN博客
相关推荐

2009-08-14 10:16:57

C#运算符重载

2009-08-12 10:47:03

C#运算符重载

2009-08-12 10:27:12

C#运算符重载运算符重载实例

2009-09-04 13:18:10

C#允许运算符重载

2009-08-12 10:56:47

C#运算符重载C#运算符重载实例

2009-08-12 12:46:11

C#运算符重载

2009-08-12 10:37:13

C#运算符重载

2009-08-19 16:59:25

C# 操作符

2009-08-11 15:51:08

C#运算符算术运算符

2009-08-12 09:30:10

C#??运算符

2009-08-12 15:02:49

C#赋值运算符简单赋值运算符

2009-11-06 13:57:52

C#

2009-08-12 15:20:18

C#赋值运算符复合赋值运算符

2009-08-11 14:16:38

C# New运算符

2009-09-01 10:08:57

C#运算符

2009-08-12 14:29:32

C#条件运算符

2009-08-12 13:35:22

C#关系运算符

2009-08-12 14:49:33

C#移位运算符

2021-12-15 10:25:57

C++运算符重载

2011-07-15 01:34:36

C++重载运算符
点赞
收藏

51CTO技术栈公众号