C # Abstract Class operator overloading

I have an abstract Vector class that I would like to overload the operators +, -, *, etc.
I want any derived classes to be able to use them and return an object of the same type as the calling object.
I tried with generics (briefly below), but I could not find a legal way to do this:

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

Then I tried to do this simply using the base class:

  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}); } 

If this method is passed in two child objects, it must perform an operation on them and return a new object of the same heritage.

The problem I am facing is that I cannot guarantee that all such child classes must have a constructor with the appropriate signature, and I cannot call the base constructor to create the object.

What are the ways to either (a) do any of these work, or (b) do it elegantly differently?

+6
source share
3 answers

You can declare abstract methods at the instance level that your subclass can override:

 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 } } 

There may be some problems, especially with several subclasses (Will SubVector should know how to add using SomeOtherSubVectorClass ? What if you add the ThirdVectorType class?) And possibly handle null cases. Also, make sure SubVector.Add behaves the same as SomeOtherSubVectorClass.Add when it comes to commutative operations.

EDIT: based on your other comments, you could be something like:

 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 } } 

EDITx2:

Given your last comment, maybe you should just maintain an internal array / matrix and just do the math. Your subclasses can display wrappers of X / Y / Z properties by array:

 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: based on your last comment, I assume that you can implement operator overloads on each subclass, make general logic in a static method (say, in the Vector base class), and do a switch / case check somewhere to provide a specific subclass :

  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? } } } 

Then your subclasses will have:

  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); } } 

Some duplication, but I don’t see a way around it from above to allow the compiler to do this:

  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); 

or for other measurements:

  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! 
+11
source

How about having an abstract method called Add (), which the + operator just acts as a wrapper? those. "return v1.Add (v2)". It will also allow you to define interfaces that non-vector classes can hold back their code, allowing you to perform mathematical operations (since the general code cannot see / touch operators like +, -, etc. For any type).

The only constructor that you can code in a general method is the default constructor (i.e., without a parameter), which you must specify in the general constraints for the method / type.

0
source

Five years later, I had the same problem, only I called them Ntuples, not vectors. Here is what I did:

 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 
0
source

Source: https://habr.com/ru/post/918042/


All Articles