从矢量来看运算符重载
运算符重载的关键是在对象上不能总是只调用方法或属性,有时还需要做一些其他工作,例如,对数值进行相加、相乘或逻辑操作。假定已经定义了一个表示数学矩阵的类,定义矩阵的相加和相乘就必须用到运算符重载,在许多情况下,重载运算符允许生成可读性更高、更直观的代码。
定义一个结构Vector包含成员字段、构造函数和重写的一个ToString()方法,最后重载运算符+和*
struct Vector { private double z; private double x; private double y; public double X { get => x; set => x = value; } public double Y { get => y; set => y = value; } public double Z { get => z; set => z = value; } public Vector(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public Vector(Vector rhs) { this.x = rhs.X; this.y = rhs.Y; this.z = rhs.Z; } public override string ToString() { return "( " + X + " , " + Y + " , " + Z + " )"; } public static Vector operator +(Vector lhs, Vector rhs) { Vector result = new Vector(lhs); result.X += rhs.X; result.Y += rhs.Y; result.Z += rhs.Z; return result; } public static Vector operator *(double lhs, Vector rhs) { return new Vector(lhs * rhs.X, lhs * rhs.Y, lhs * rhs.Z); } public static Vector operator *(Vector lhs, double rhs) { return rhs * lhs; } public static double operator *(Vector lhs, Vector rhs) { return lhs.X * rhs.X + lhs.Y + rhs.Y + lhs.Z * rhs.Z; } public static bool operator ==(Vector lhs, Vector rhs) { if (lhs.Equals(rhs)) return true; else return false; } public static bool operator !=(Vector lhs, Vector rhs) { return !(lhs == rhs); } /// <summary> /// 比较两个vector 是否相等 /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { var vector = obj as Vector?; if (obj == null) return false; if (this.X.Equals(vector.GetValueOrDefault().X) && this.Y.Equals(vector.GetValueOrDefault().Y) && this.Z.Equals(vector.GetValueOrDefault().Z)) return true; else return false; } /// <summary> /// 返回结构的HashCode /// </summary> /// <returns></returns> public override int GetHashCode() { return this.X.GetHashCode()+this.Y.GetHashCode()+this.Z.GetHashCode(); }
从上可以看出运算符重载都声明为Public和static,这表示它们与它们的类结构相关联,而不是与某个特定实例相关,所以运算符重载的代码不能访问非静态成员,也不能访问this标识符。
从上面我们可以看出在比较两个对象相等时,使用了重写object基类的equals方法来比较对象的属性是否一一相等,在比较对象相等性共有四个版本:ReferenceEquals()和两个版本的Equals(),还有比较运算符==。
ReferenceEquals()方法是一个静态方法,比较两个引用是否引用类的同一个实例,特别是两个引用是否包含内存中的相同地址。作为静态方法,它不能重写,所以System.Object的实现代码保持不变。如果提供的两个引用引用同一个对象实例,则ReferenceEquals()总是返回true;否则就返回false。但是它认为null等于null。
虚拟的Equals()方法,在自己的类中重写它,从而按照所需来比较对象,特别是如果希望类的实例用作字典中的键,就需要重写这个方法,以比较相关值。
静态的Equals()方法,带有两个参数,并对它们进行相等性比较,这个方法可以处理两个对象中有一个是null的情况,静态重载版本首先要检查传递给它的引用是否为null,如果都是null就返回true,如果只有一个引用是null,它就返回fals,如果两个引用实际上引用了某个对象,它就调用Equals()的虚拟实现版本,这表示在重写Equals()的实例版本时,其效果相当于也重写了静态版本。
==在大多数情况下的代码表示比较引用,在结构中最好重写比较运算符,以执行值的比较,System.String类微软重写了这个运算符以比较字符串的内容而不是比较它们的引用。
测试上面所写结构Vector
// stuff to demonstrate arithmetic operations Vector vect1, vect2, vect3,vect4; vect1 = new Vector(1.0, 1.5, 2.0); vect2 = new Vector(0.0, 0.0, -10.0); vect3 = vect1 + vect2; vect4 = new Vector(1.0, 1.5, 2.0); var result = (vect4 == vect1); Console.WriteLine("vect1 = " + vect1); Console.WriteLine("vect2 = " + vect2); Console.WriteLine("vect3 = vect1 + vect2 = " + vect3); Console.WriteLine("2*vect3 = " + 2 * vect3); vect3 += vect2; Console.WriteLine("vect3+=vect2 gives " + vect3); vect3 = vect1 * 2; Console.WriteLine("Setting vect3=vect1*2 gives " + vect3); double dot = vect1*vect3; Console.WriteLine("vect1*vect3 = " + dot); Console.ReadLine();
可以看出我们重写的equals()方法在对对象的值进行一一比较,其中引用了double结构重写的equals方法