C# 抽象类运算符重载

本文关键字:重载 运算符 抽象类 | 更新日期: 2023-09-27 18:37:10

我有一个抽象类,Vector,我想重载运算符+,-,*等。
我希望任何派生类都能够使用这些类,并获取与调用对象类型相同的对象。
我尝试使用泛型(简而言之,如下所示),但我找不到合法的方法:

public static T operator +<T>( T V1, T V2) where T : Vector
{
     //some calculation
     return new T(args);
}

然后我尝试仅使用基类来执行此操作:

    public static Vector operator+(Vector V1, Vector V2)
    {
        if (V1.Dimension != V2.Dimension)
            throw new VectorTypeException("Vector Dimensions Must Be Equal");
        double[] ArgList = new double[V1.Dimension];
        for (int i = 0; i < V1.Dimension; i++) { ArgList[i] = V1[i] + V2[i]; }
        return (Vector)Activator.CreateInstance(V1.GetType(), new object[] { ArgList});
    }

如果此方法在两个子对象中传递,则应对它们执行操作,并返回具有相同遗产的新对象。

遇到的问题是,我无法强制所有此类子类都必须具有具有适当签名的构造函数,并且我无法调用基构造函数来制作对象。

有什么方法可以(a)使这些工作中的任何一个工作,或(b)以另一种方式优雅地做到这一点?

C# 抽象类运算符重载

您可以声明子类可以覆盖的实例级抽象方法:

public abstract class Vector
{
    protected abstract Vector Add(Vector otherVector);
    public static Vector operator +(Vector v1, Vector v2)
    {
        return v1.Add(v2);
    }
}
public class SubVector : Vector
{
    protected override Vector Add(Vector otherVector)
    {
        //do some SubVector addition
    }
}

可能会遇到一些问题,尤其是多个子类(SubVector必须知道如何添加SomeOtherSubVectorClass吗? 如果添加ThirdVectorType类怎么办?也许可以处理空案例。 此外,确保SubVector.Add在交换操作时的行为与SomeOtherSubVectorClass.Add相同。

编辑:根据您的其他评论,您可以像这样:

public class Vector2D : Vector
{
    public double X { get; set; }
    public double Y { get; set; }
    protected override Vector Add(Vector otherVector)
    {
        Vector2D otherVector2D = otherVector as Vector2D;
        if (otherVector2D != null)
            return new Vector2D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y };
        Vector3D otherVector3D = otherVector as Vector3D;
        if (otherVector3D != null)
            return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = otherVector3D.Z };
        //handle other cases
    }
}

public class Vector3D : Vector
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
    protected override Vector Add(Vector otherVector)
    {
        Vector2D otherVector2D = otherVector as Vector2D;
        if (otherVector2D != null)
            return new Vector3D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y, Z = this.Z };
        Vector3D otherVector3D = otherVector as Vector3D;
        if (otherVector3D != null)
            return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = this.Z + otherVector3D.Z };
        //handle other cases
    }
}

编辑x2:

鉴于您的最新评论,也许您应该只维护一个内部数组/矩阵,然后只做通用矩阵数学。 子类可以针对数组指示公开 X/Y/Z 属性包装器:

public class Vector
{
    protected double[] Values;
    public int Length { get { return Values.Length; } }
    public static Vector operator +(Vector v1, Vector v2)
    {
        if (v1.Length != v2.Length)
        {
            throw new VectorTypeException("Vector Dimensions Must Be Equal");
        }
        else
        {
            //perform generic matrix addition/operation
            double[] newValues = new double[v1.Length];
            for (int i = 0; i < v1.Length; i++)
            {
                newValues[i] = v1.Values[i] + v2.Values[i];
            }
            //or use some factory/service to give you a Vector2D, Vector3D, or VectorND
            return new Vector() { Values = newValues };
        }
    }
}
public class Vector2D : Vector
{
    public double X
    {
        get { return Values[0]; }
        set { Values[0] = value; }
    }
    public double Y
    {
        get { return Values[1]; }
        set { Values[1] = value; }
    }
}

public class Vector3D : Vector
{
    public double X
    {
        get { return Values[0]; }
        set { Values[0] = value; }
    }
    public double Y
    {
        get { return Values[1]; }
        set { Values[1] = value; }
    }
    public double Z
    {
        get { return Values[2]; }
        set { Values[2] = value; }
    }
}

EDITx3:根据你最新的评论,我想你可以在每个子类上实现运算符重载,在静态方法中执行共享逻辑(比如在基 Vector 类中),并在某个地方进行开关/大小写检查以提供特定的子类:

    private static Vector Add(Vector v1, Vector v2)
    {
        if (v1.Length != v2.Length)
        {
            throw new VectorTypeException("Vector Dimensions Must Be Equal");
        }
        else
        {
            //perform generic matrix addition/operation
            double[] newValues = new double[v1.Length];
            for (int i = 0; i < v1.Length; i++)
            {
                newValues[i] = v1.Values[i] + v2.Values[i];
            }
            //or use some factory/service to give you a Vector2D, Vector3D, or VectorND
            switch (newValues.Length)
            {
                case 1 :
                    return new Vector1D() { Values = newValues };
                case 2 :
                    return new Vector2D() { Values = newValues };
                case 3 :
                    return new Vector3D() { Values = newValues };
                case 4 :
                    return new Vector4D() { Values = newValues };
                //... and so on
                default :
                    throw new DimensionOutOfRangeException("Do not support vectors greater than 10 dimensions");
                    //or you could just return the generic Vector which doesn't expose X,Y,Z values?
            }
        }
    }

然后,您的子类将具有:

    public class Vector2D
    {
        public static Vector2D operator +(Vector2D v1, Vector2D v2)
        {
            return (Vector2D)Add(v1, v2);
        }
    }
    public class Vector3D
    {
        public static Vector3D operator +(Vector3D v1, Vector3D v2)
        {
            return (Vector3D)Add(v1, v2);
        }
    }

一些重复,但我看不到允许编译器执行此操作的方法:

    Vector3 v1 = new Vector3(2, 2, 2);
    Vector3 v2 = new Vector3(1, 1, 1);
    var v3 = v1 + v2; //Vector3(3, 3, 3);
    Console.WriteLine(v3.X + ", " + v3.Y + ", " + v3.Z);

或者对于其他尺寸:

    Vector2 v1 = new Vector2(2, 2);
    Vector2 v2 = new Vector2(1, 1);
    var v3 = v1 + v2; //Vector2(3, 3, 3);
    Console.WriteLine(v3.X + ", " + v3.Y); // no "Z" property to output!

有一个叫做Add()的抽象方法,operator+只是充当包装器怎么样? 即,"返回 v1。添加(v2)"。这也将使您能够定义非 Vector 类可以约束其代码的接口,从而能够执行类似数学的操作(因为泛型代码看不到/触摸任何类型的 +、- 等运算符)。

可以在泛型方法

中使用的唯一构造函数是默认(即无参数)构造函数,您必须在方法/类型的泛型约束中指定该构造函数。

五年后,我遇到了完全相同的问题,只是我称它们为Ntuples,而不是向量。这是我所做的:

using System;
using System.Collections.Generic;
  public class Ntuple{
    /*parent class
    has an array of coordinates
    coordinate-wise addition method
    greater or less than in dictionary order
    */
    public List<double> Coords = new List<double>();
    public int Dimension;
    public Ntuple(List<double> Input){
      Coords=Input;
      Dimension=Input.Count;
    }//instance constructor
    public Ntuple(){
    }//empty constructor, because something with the + overload?

   public static Ntuple operator +(Ntuple t1, Ntuple t2)
   {
     //if dimensions don't match, throw error
     List<double> temp = new List<double>();
     for (int i=0; i<t1.Dimension; i++){
       temp.Add(t1.Coords[i]+t2.Coords[i]);
     }
     Ntuple sum = new Ntuple(temp);
     return sum;
   }//operator overload +
   public static bool operator >(Ntuple one, Ntuple other){
     //dictionary order
     for (int i=0; i<one.Dimension; i++){
       if (one.Coords[i]>other.Coords[i]) {return true;}
     }
     return false;
   }
   public static bool operator <(Ntuple one, Ntuple other){
     //dictionary order
     for (int i=0; i<one.Dimension; i++){
       if (one.Coords[i]<other.Coords[i]) {return true;}
     }
     return false;
   }
  }//ntuple parent class

  public class OrderedPair: Ntuple{
    /*
    has additional method PolarCoords, &c
    */
    public OrderedPair(List<double> Coords) : base(Coords){}
    //instance constructor
    public OrderedPair(Ntuple toCopy){
      this.Coords=toCopy.Coords;
      this.Dimension=toCopy.Dimension;
    }
  }//orderedpair
  public class TestProgram{
    public static void Main(){
      List<double> oneCoords=new List<double>(){1,2};
      List<double> otherCoords= new List<double>(){2,3};

      OrderedPair one = new OrderedPair(oneCoords);
      OrderedPair another = new OrderedPair(otherCoords);
      OrderedPair sum1 = new OrderedPair(one + another);

      Console.WriteLine(one.Coords[0].ToString()+one.Coords[1].ToString());
      Console.WriteLine(sum1.Coords[0].ToString()+sum1.Coords[1].ToString());
      bool test = one > another;
      Console.WriteLine(test);
      bool test2 = one < another;
      Console.WriteLine(test2);
    }
  }

}//namespace ntuples