2012-06-13 33 views
6

Tôi có một lớp trừu tượng, Vector, mà tôi muốn quá tải các toán tử +, -, *, v.v.
Tôi muốn bất kỳ lớp dẫn xuất nào có thể sử dụng chúng và nhận đối tượng trở lại với cùng loại với đối tượng gọi.
tôi đã cố gắng với Generics, (như sau, tóm tắt), nhưng tôi không thể tìm thấy một cách hợp pháp để làm điều đó:C# Abstract Class Operator Overload

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

sau đó tôi đã cố gắng để làm điều đó chỉ bằng cách sử dụng lớp cơ sở:

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

Nếu phương pháp này được truyền vào hai đối tượng con, nó phải thực hiện thao tác trên chúng và trả về một đối tượng mới của cùng một di sản. Vấn đề tôi gặp phải với điều này là tôi không thể thực thi tất cả các lớp con đó phải có một hàm tạo với chữ ký thích hợp, và tôi không thể gọi hàm tạo cơ sở để tạo đối tượng.

Cách thức để (a) Thực hiện một trong những công việc này, hoặc (b) thực hiện điều này một cách thanh lịch theo cách khác?

+0

Lớp học có nguồn gốc của bạn trông như thế nào? – JotaBe

+0

Có vẻ lạ với tôi rằng bạn sẽ cần phải phân lớp 'Vector' (xuất hiện chủ yếu là một mảng' double'.) Bạn có thể giải thích thêm một chút về thứ bậc của bạn không? – dlev

+0

Kết quả của 'VectorA + VectorB' là gì, giả sử cả hai bắt nguồn từ' Vector'? –

Trả lời

10

Bạn có thể tuyên bố phương pháp trừu tượng dụ cấp mà lớp con của bạn có thể ghi đè lên:

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

Có thể gặp phải một số vấn đề đặc biệt với nhiều lớp con (Will SubVector đã biết làm thế nào để thêm với SomeOtherSubVectorClass gì nếu bạn thêm ThirdVectorType lớp?) Và có thể xử lý các trường hợp null. Ngoài ra, hãy đảm bảo rằng SubVector.Add hoạt động giống như SomeOtherSubVectorClass.Add khi nói đến các hoạt động giao hoán.

EDIT: dựa trên ý kiến ​​khác của bạn, bạn có thể để một cái gì đó như:

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:

Với bình luận mới nhất của bạn, có lẽ bạn chỉ nên duy trì một mảng nội bộ/ma trận và chỉ làm chung ma trận toán học. lớp con của bạn có thể tiếp xúc với giấy gói X/Y/sở hữu Z so với indicies mảng:

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: Dựa trên nhận xét mới nhất của bạn, tôi đoán bạn có thể thực hiện quá tải toán tử trên mỗi lớp con, làm logic được chia sẻ trong một phương pháp tĩnh (nói trong lớp cơ sở Vector), và ở đâu đó làm một tấm séc chuyển/trường hợp để cung cấp một lớp con cụ thể:

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

Sau đó, lớp con của bạn sẽ có:

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

Một số sự trùng lặp, nhưng tôi không nhìn thấy một con đường xung quanh nó ra khỏi đỉnh đầu của tôi để cho phép trình biên dịch để làm điều này:

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

hoặc cho không gian khác:

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! 
+0

Trong trường hợp tôi đang sử dụng, Vectors chỉ có thể cộng lại với nhau nếu chúng có cùng chiều dài. Tôi chủ yếu cố gắng cho hành vi vector thích hợp. Nhưng vì tất cả các vector thứ nguyên thêm vào cùng một cách, chỉ với một số lượng đối số khác nhau, tôi chỉ muốn viết một lần. – 3Pi

+0

Ahh, tôi đã chỉnh sửa sau nhận xét này. Có lẽ sau đó bạn nên xử lý các vectơ của bạn với các mảng được lập chỉ mục? Làm một số kiểm tra chiều dài và thực hiện các phép toán ma trận khi cần thiết theo một cách chung chung? –

+0

Đó là cơ bản những gì tôi đã có, và đăng. Nơi mà tôi nhận được bối rối là bit nơi đúc/tạo đối tượng mới xảy ra. Nếu đối tượng trả về được tạo ra như một lớp con, nhưng được truyền ra như là một lớp cha, nó có thể được trả về lớp con không? – 3Pi

0

gì về việc có một phương thức trừu tượng có tên là Add() mà toán tử + chỉ hoạt động như một trình bao bọc? tức là "return v1.Add (v2)".Điều này cũng sẽ cho phép bạn định nghĩa các giao diện mà các lớp không phải Vector có thể hạn chế mã của chúng, cho phép thực hiện các hoạt động giống như toán học (vì mã chung không thể nhìn thấy/chạm toán tử như +, -, v.v. cho bất kỳ loại nào).

Phương thức khởi tạo duy nhất bạn có thể viết bằng phương thức chung là hàm tạo mặc định (ví dụ, tham số-ít), mà bạn phải chỉ định trong các ràng buộc chung cho phương thức/kiểu.

0

Năm năm sau, tôi đã có cùng một vấn đề chính xác, chỉ có tôi gọi họ là Ntuples chứ không phải là vectơ. Đây là những gì tôi đã làm:

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