2012-06-13 28 views
6

Soyut bir sınıf var, Vektör, hangi operatörlere yüklenmek istiyorum +, -, *, vb
Bunlardan türetilmiş sınıfların bunları kullanabilmesini ve bir nesne almasını istiyorum çağıran nesne ile aynı türden.
Ben (aynı kısaca aşağıdaki), jenerik ile çalıştı, ama bunu yapmak için yasal bir yolunu bulamadı:C# Soyut Sınıf İşleci Aşırı Yükleme

: sadece temel sınıfını kullanarak ben o zaman yapmaya çalıştığım

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

Bu yöntem iki alt nesneye aktarılırsa, bu işlem üzerinde işlem yapmalı ve aynı mirasın yeni nesnesini döndürmelidir.

Karşılaştığım sorun, tüm bu alt sınıfların uygun imzaya sahip bir kurucunun olması zorunluluğunu uygulayamayacağım ve nesneyi yapmak için temel kurucuyu arayamıyorum.

(a) Bu çalışmalardan herhangi birini yapın veya (b) bunu başka şekilde zarif bir şekilde yapın? eklerseniz ne

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

SomeOtherSubVectorClass ile nasıl ekleneceğini bilmek (özellikle çoklu alt sınıfları bazı sorunlarla Will SubVector var çalıştırmak olabilir:?

+0

Türetilmiş sınıflarınız nasıl görünüyor? – JotaBe

+0

Bana “Vector” alt sınıfını (temelde "double" dizisi gibi görünen) almanız gerekecek garip görünüyor. Hiyerarşiniz hakkında biraz daha açıklayabilir misiniz? – dlev

+0

Her ikisi de 'Vector' türetilerek, VectorA + VectorB' nin sonucu ne olurdu? –

cevap

10

Sen alt sınıf geçersiz kılabilir örnek düzeyi soyut yöntemler olduğuna dair karar ThirdVectorType sınıfı?) Ve belki de boş durumları ele almak. Ayrıca, değiştirici işlemler söz konusu olduğunda SubVector.Add'un SomeOtherSubVectorClass.Add ile aynı olduğundan emin olun.

DÜZENLEME: diğer açıklamalara dayanarak, bunu gibi bir şey olabilir:

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:

en son açıklama göz önüne alındığında, belki de senin sadece bir iç dizi/matris korumak ve gerektiği jenerik yapmak matris matrisi. Sizin alt sınıfları dizisi indicies karşı X/Y/Z mülkiyet sarmalayıcılarını maruz bırakabilir:

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: En son comment dayanarak, statik yöntemle paylaşılan mantığı yapmak, her alt sınıf üzerindeki operatör aşırı yükleme yaparak uygulamak sanırım (baz Vektör sınıfta söylemek) ve bir yere belirli bir alt sınıfı sağlamak için bir anahtar/case kontrolü yapmak:

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

Sonra alt sınıfları olurdu:

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

veya diğer boyutlar:

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

Kullanmakta olduğum durumlar söz konusu olduğunda, Vektörler sadece aynı uzunluktakiler ile birbirlerini toplayabilirler. Aslında doğru vektör davranışını deniyorum. Ancak tüm boyut vektörleri aynı şekilde eklendiğinden, sadece farklı sayıda argüman ile, sadece bir kez yazmak istiyorum. – 3Pi

+0

Ahh, Bu yorumun ardından düzenledim. Belki de vektörlerinizi endeksli diziler ile ele almalısınız? Bazı uzunluk kontrolleri yapın ve matris matematiğini genel bir şekilde gerektiği gibi yapın? –

+0

Bu, zaten sahip olduğum ve gönderdiğim şey. Kafamın karıştığı yer, döküm/yeni nesne oluşturmanın gerçekleştiği noktadır. Dönüş nesnesi bir alt sınıf olarak oluşturulduysa, ancak üst sınıf olarak iletildiyse, alt sınıfa döndürebilir mi? – 3Pi

0

ne sahip yaklaşık 10 Bazı çoğaltılması, ama derleyici bunu yapmak için izin başımın üstü kapalı çevresinde bir yol göremiyorum Operatörün sadece sarıcı olarak davrandığı Add() adında soyut bir yöntem mi? yani "v1.Add (v2)" değerini döndür.Bu ayrıca, Vector dışı sınıfların kodlarını sınırlandırabilmelerini, matematik benzeri işlemleri gerçekleştirebilmelerini sağlamanızı (genel kod, herhangi bir tür için +, - vb. Gibi operatörleri göremez/bunlara dokunamaz) tanımlamanızı sağlar.

Genel bir yöntemle kodlayabileceğiniz tek kurucu, yöntem/tür için genel kısıtlamalarda belirtmeniz gereken varsayılan (yani, parametre az) yapıcıdır.

0

Beş yıl sonra aynı problemi yaşadım, sadece onlara Ntuples diyordum, vektörler değil. İşte yaptığım şey:

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