操作符重载是指允许用户使用用户定义的类型编写表达式的能力。
例如,通常需要编写类似于以下内容的代码,以将两个数字相加。很明显,sum 是两个数字之和。
int i = 5;
int sum = i + j;
如果可以使用代表复数的用户定义的类型来编写相同类型的表达式,那当然是最好不过了:
Complex i = 5;
Complex sum = i + j;
运算符重载允许为用户定义的类型重载(即指定明确的含义)诸如“+”这样的运算符。如果不进行重载,则用户需要编写以下代码:
Complex i = new Complex(5);
Complex sum = Complex.Add(i, j);
此代码可以很好地运行,但 Complex 类型并不能象语言中的预定义类型那样发挥作用。
操作符重载语法:
语法:
public static 返回值类型 operator 操作符 (类型)
实例:
public static Fraction operator +(Fraction lhs, Fraction rhs)
{
}
分数操作符重载
... {
// 属性 //#region // 属性 //
private int numerator;
public int Numerator
...{
get
...{
return numerator;
}
set
...{
numerator = value;
}
}
private int denominator;
public int Denominator
...{
get
...{
return denominator;
}
set
...{
if (value != 0)
denominator = value;
else
Console.WriteLine("分母不能小于零");
}
}
#endregion
// 构造函数 //#region // 构造函数 //
public Fraction(int numerator, int denominator)
...{
this.Denominator = denominator;
this.Numerator = numerator;
}
public Fraction(int wholeNumber):this(wholeNumber,1)
...{
//this.denominator = 1;
//this.numerator = wholeNumber;
}
#endregion
public static Fraction operator +(Fraction lhs, Fraction rhs)
...{
if (lhs.Denominator == rhs.Denominator)
...{
return new Fraction(lhs.numerator + rhs.numerator, lhs.denominator);
}
else
...{
int temp1 = lhs.denominator * rhs.numerator;
int temp2 = lhs.numerator * rhs.Denominator;
return new Fraction(temp1 + temp2, lhs.denominator * rhs.denominator);
}
}
public override string ToString()
...{
if (this.denominator != 1)
...{
return this.numerator.ToString() + "/" + this.denominator;
}
else
...{
return this.numerator.ToString();
}
}
public static implicit operator Fraction(int theInt)
...{
return new Fraction(theInt);
}
public static explicit operator int(Fraction theFraction)
...{
return theFraction.numerator / theFraction.denominator;
}结果为:
... {
分数#region 分数
Fraction f1 = new Fraction(1, 5);
Fraction f2 = new Fraction(1, 6);
Fraction f = f1 + f2;
Console.WriteLine("{0}+{1}={2}", f1.ToString(), f2.ToString(), f.ToString());
int a = (int)f;
Console.WriteLine(a);
f = 3;
Console.WriteLine(f.ToString());
#endregion
}
1/5+1/6=11/30
0
3
implicit为隐式转换操作符重载
explicit为显示转换操作符重载
创建有用的操作符:
任何事情都有特定的时间和场所,操作符重载是一个容易引起误解的语言功能,而且编程人员对待它的态度也大相径庭。一些人认为:用户使用这一功能编写的程序将令人费解,而且它也不应归于编程语言。另一些人则认为它是一个很不错的功能,在任何地方都可以使用。 这两种观点既包含正确的成分,但也有欠妥之处。应该承认,运算符重载可能会导致编写出的程序令人费解,但根据我的经验,即使不使用运算符重载,也很可能编写出令人费解的代码。在某些情况下,不使用重载甚至会使代码更加令人费解。那些不分场合、随意使用重载的人“确实”在生产令人费解的代码。
在语言中之所以使用重载,是为了在概念上对用户的类或结构进行简化。只有在有助于提高用户所写代码的可读性时,才能对运算符进行重载。请注意,我们所说的检验标准是“更清晰”,而不是“更简短”。运用了运算符重载的类几乎总是会使代码变得更简短,但并不能每次都使代码变得更清晰(即可读性更强)。
为了说明这一点,我创建了多个重载示例。您需要仔细阅读这些代码,想一想哪个运算符进行了重载,重载的运算符执行了什么运算。
测验
i
BigNum n1 = new BigNum("123456789012345");
BigNum n2 = new BigNum("11111");
BigNum sum = n1 + n2;
ii
Matrix m1 = loadMatrix();
Matrix m2 = loadMatrix();
Matrix result = m1 * m2;
iii
DBRow row = query.Execute();
while (!row.Done)
{
Viewer.Add(row);
row++;
}
IV
Account current = findAccount(idNum);
current += 5;
i 、本示例中,要执行的运算是显而易见的。这种加法只不过是将预定义的类型相加,每个人都明白执行了什么运算,因此在这个示例中,使用运算符重载很有意义。
ii、本示例演示了矩阵如何相乘。从概念上来说,矩阵乘法与常规乘法不完全类似,但它是一个明确定义的运算,因此任何理解矩阵乘法的人看到这种重载的运算符时,都不会感到惊讶。
iii、本示例中,增量 (++) 运算符进行了重载,它使数据库行向前移至下一行。任何与数据库行有关的事物都不可能使我们理解这种增量的真正含义,而且,这种增量要执行的运算也不是那么明显。
在这一示例中,重载的使用也没有使代码变得更简单。如果我们转而使用以下代码,情况就好多了: DBRow row = query.Execute();
while (!row.MoveNext())
{
Viewer.Add(row);
}
IV、将事物和雇员相加代表什么含义呢?本示例中,选择是一个不错的方法,将其与雇员数相加就会注册雇员。这是一种很糟糕的运算符重载用法。