2012-06-13 11 views
6

मेरे पास एक अमूर्त वर्ग, वेक्टर है, जिसे मैं ऑपरेटरों +, -, *, आदि को अधिभारित करना चाहता हूं
मैं चाहता हूं कि कोई व्युत्पन्न कक्षाएं इनका उपयोग करने में सक्षम हों, और ऑब्जेक्ट प्राप्त करें कॉलिंग ऑब्जेक्ट के समान प्रकार के साथ वापस।
मैं जेनरिक के साथ की कोशिश की, (के रूप में इस प्रकार है, संक्षेप में), लेकिन मैं यह करने के लिए एक कानूनी रास्ता नहीं मिल सका:सी # सार कक्षा ऑपरेटर अधिभार

:

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

यदि यह विधि दो बच्चों की वस्तुओं में पारित की जाती है, तो उन्हें ऑपरेशन करना चाहिए, और उसी विरासत की एक नई वस्तु वापस करनी चाहिए।

जिस समस्या में मैंने भाग लिया वह यह है कि मैं यह लागू नहीं कर सकता कि ऐसे सभी बाल वर्गों में उपयुक्त हस्ताक्षर के साथ एक निर्माता होना चाहिए, और मैं वस्तु बनाने के लिए आधार निर्माता को कॉल नहीं कर सकता।

या तो (ए) इन तरीकों में से किसी एक को बनाने के तरीके क्या हैं, या (बी) इसे किसी अन्य तरीके से सुंदर तरीके से करें? ?

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 साथ जोड़ने के बारे में पता करने के लिए क्या होगा यदि आप जोड़ें:

+0

आपके व्युत्पन्न वर्ग कैसा दिखते हैं? – JotaBe

+0

यह मेरे लिए अजीब लगता है कि आपको 'वेक्टर' को उप-वर्ग करना होगा (जो मुख्य रूप से 'डबल' की सरणी प्रतीत होता है।) क्या आप अपने पदानुक्रम के बारे में कुछ और बता सकते हैं? – dlev

+0

'वेक्टर' + वेक्टर बी 'का नतीजा क्या होगा, मानते हैं कि दोनों' वेक्टर 'से प्राप्त होते हैं? –

उत्तर

10

आप उदाहरण के स्तर के सार तरीकों जो आपके उपवर्ग ओवरराइड कर सकते हैं की घोषणा कर सकता है 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 
    } 
} 

EDITx2:

अपने नवीनतम टिप्पणी को देखते हुए, शायद अपने बस एक आंतरिक सरणी/मैट्रिक्स को बनाए रखने और चाहिए सिर्फ सामान्य कर मैट्रिक्स गणित। आपका उपवर्गों सरणी indicies के खिलाफ एक्स/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: अपने नवीनतम टिप्पणी के आधार पर, मुझे लगता है कि आप प्रत्येक उपवर्ग पर ऑपरेटर भार के लागू कर सकता है, एक स्थिर विधि में साझा तर्क करना (आधार वेक्टर कक्षा में कहते हैं), और कहीं एक विशिष्ट उपवर्ग प्रदान करने के लिए एक स्विच/मामले की जांच करते हैं:

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

यदि मैं उपयोग कर रहा हूं, तो वेक्टर एक दूसरे के साथ मिल सकते हैं यदि वे एक ही लंबाई हैं। मैं अनिवार्य रूप से उचित वेक्टर व्यवहार की कोशिश कर रहा हूं। लेकिन चूंकि सभी आयाम वैक्टर एक ही तरीके से जोड़ते हैं, केवल तर्कों की एक अलग संख्या के साथ, मैं इसे केवल एक बार लिखना चाहता हूं। – 3Pi

+0

आह, मैंने इस टिप्पणी के बाद संपादित किया। शायद तब आपको अपने वैक्टरों को अनुक्रमित सरणी के साथ इलाज करना चाहिए? कुछ लंबाई जांच करें और एक सामान्य तरीके से आवश्यक मैट्रिक्स गणित करें? –

+0

यह अनिवार्य रूप से मेरे पास पहले से ही है, और पोस्ट किया गया है। जहां मैं उलझन में हूं, वह छोटा सा है जहां कास्टिंग/नई वस्तु निर्माण होती है। यदि वापसी वस्तु को बाल वर्ग के रूप में बनाया गया है, लेकिन माता-पिता वर्ग के रूप में पारित किया गया है, तो क्या इसे बाल वर्ग में वापस कर दिया जा सकता है? – 3Pi

0

क्या होने के बारे में Add() नामक एक अमूर्त विधि है कि ऑपरेटर + सिर्फ एक रैपर के रूप में कार्य करता है? यानी, "वापसी v1.Add (v2)"।यह आपको इंटरफेस को परिभाषित करने में भी सक्षम बनाता है जो गैर-वेक्टर कक्षाएं गणित की तरह संचालन करने में सक्षम होने के लिए अपने कोड को बाधित कर सकती हैं (चूंकि जेनेरिक कोड किसी भी प्रकार के लिए +, - आदि जैसे ऑपरेटरों को नहीं देख सकता/स्पर्श कर सकता है)।

एकमात्र निर्माता जो आप सामान्य विधि में कोड कर सकते हैं वह डिफ़ॉल्ट (यानी, पैरामीटर-कम) कन्स्ट्रक्टर है, जिसे आपको विधि/प्रकार के लिए सामान्य बाधाओं में निर्दिष्ट करना है।

0

पांच साल बाद मुझे एक ही समस्या थी, केवल मैं उन्हें नटुपल्स कह रहा था, वैक्टर नहीं। यहां मैंने किया है:

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