ऑपरेटर ओवरलोडिंग के उदाहरण, जो समझ में आते हैं [बंद]


12

जब मैं C # सीख रहा था, मैंने पाया कि, C # ऑपरेटर ओवरलोडिंग का समर्थन करता है। मुझे अच्छे उदाहरण के साथ समस्या है जो:

  1. समझदारी बनाएं (भेड़ और गाय नाम का वर्ग जोड़ना)
  2. दो तार के मिलन का उदाहरण नहीं है

बेस क्लास लाइब्रेरी के उदाहरणों का स्वागत है।


10
कृपया 'भाव' को परिभाषित करें! गंभीरता से, इस बिंदु पर सटीक और कड़वी बहस इस बात को दर्शाती है कि वास्तव में इस बारे में बड़ी असहमति है। कई अधिकारी ओवरलोड ऑपरेटरों को अस्वीकार करते हैं क्योंकि उन्हें पूरी तरह से अप्रत्याशित चीजें करने के लिए बनाया जा सकता है। अन्य लोग जवाब देते हैं कि इसी तरह विधि नामों को पूरी तरह से अचिंत्य चुना जा सकता है, लेकिन यह नाम कोड ब्लॉक को अस्वीकार करने का कोई कारण नहीं है! आप लगभग निश्चित रूप से किसी भी उदाहरण को प्राप्त नहीं करने जा रहे हैं जिन्हें आमतौर पर समझदार माना जाता है। उदाहरण जो आपको समझदार लगते हैं - शायद।
किलन फ़ॉथ

पूरी तरह से @KilianFoth से सहमत हैं। अंतत: जो कार्यक्रम संकलित करता है, वह संकलक को समझ में आता है। लेकिन अगर ==गुणा करने के लिए अधिभार , यह मेरे लिए समझ में आता है, लेकिन दूसरों के लिए समझ में नहीं आ सकता है! क्या यह सवाल है कि हम किस सुविधा प्रोग्रामिंग भाषाओं की वैधता के बारे में बात कर रहे हैं या हम 'सर्वोत्तम प्रथाओं को कोडिंग' के बारे में बात कर रहे हैं?
दीपन मेहता

जवाबों:


27

उपयुक्त ऑपरेटर ओवरलोडिंग के स्पष्ट उदाहरण किसी भी वर्ग हैं जो उसी तरह से व्यवहार करते हैं जैसे संख्याएं संचालित होती हैं। तो BigInt वर्गों (के रूप में Jalayn पता चलता है), जटिल संख्याओं या मैट्रिक्स वर्गों (के रूप में Superbest पता चलता है) सब, एक ही कार्य है कि साधारण संख्या तो गणितीय ऑपरेटर पर वास्तव में अच्छी तरह से मैप किया है, जबकि समय परिचालन (के रूप में द्वारा सुझाए गए svick ) अच्छी तरह से एक सबसेट पर नक्शा उन कार्यों के।

थोड़ा और अधिक संक्षेप में, ऑपरेटरों जब प्रदर्शन के लिए इस्तेमाल किया जा सकता है की तरह सेट संचालन, तो operator+एक हो सकता है संघ , operator-हो सकता है एक पूरक , आदि यह प्रतिमान हालांकि फैलाने के लिए शुरू होता है खासकर यदि आप इसके अलावा या एक ऑपरेशन जो 'isn के लिए गुणा ऑपरेटर का उपयोग टी कम्यूटेटिव , जैसा कि आप उनसे उम्मीद कर सकते हैं।

C # अपने आप में नॉन-न्यूमेरिक ऑपरेटर ओवरलोडिंग का एक उत्कृष्ट उदाहरण है । इसका उपयोग +=और प्रतिनिधियों-= को जोड़ने और घटाना है , अर्थात उन्हें रजिस्टर और डी-रजिस्टर करना। यह अच्छी तरह से काम करता है क्योंकि और ऑपरेटर काम करते हैं जैसा कि आप उनसे उम्मीद करेंगे, और इसका परिणाम बहुत अधिक संक्षिप्त कोड में होगा।+=-=

प्यूरिस्ट के लिए, स्ट्रिंग +ऑपरेटर के साथ समस्याओं में से एक यह है कि यह कम्यूटेटिव नहीं है। "a"+"b"जैसा है वैसा नहीं है "b"+"a"। हम स्ट्रिंग्स के लिए इस अपवाद को समझते हैं क्योंकि यह बहुत आम है, लेकिन हम यह कैसे बता सकते हैं कि operator+अन्य प्रकारों का उपयोग कम्यूटेटिव होगा या नहीं? अधिकांश लोग यह मान लेंगे कि यह तब तक है, जब तक कि वस्तु स्ट्रिंग-जैसी नहीं है , लेकिन आप वास्तव में कभी नहीं जानते कि लोग क्या मानेंगे।

स्ट्रिंग्स के साथ, मैट्रिस के फॉयबल्स बहुत अच्छी तरह से जाने जाते हैं। यह स्पष्ट है कि Matrix operator* (double, Matrix)एक अदिश गुणन है, जबकि उदाहरण के लिए Matrix operator* (Matrix, Matrix)एक मैट्रिक्स गुणा (यानी डॉट-उत्पाद गुणन का एक मैट्रिक्स) होगा।

इसी तरह प्रतिनिधियों के साथ ऑपरेटरों का उपयोग स्पष्ट रूप से गणित से बहुत दूर है कि आप उन गलतियों को करने की संभावना नहीं है।

संयोग से, 2011 के एसीसीयू सम्मेलन में , रोजर ऑर एंड स्टीव लव ने कुछ वस्तुओं पर एक सत्र प्रस्तुत किया, जो दूसरों की तुलना में अधिक समान हैं - समानता, मूल्य और पहचान के कई अर्थों पर एक नज़रफ्लोटिंग पॉइंट समानता के बारे में रिचर्ड हैरिस के परिशिष्ट के रूप में उनकी स्लाइड डाउनलोड करने योग्य हैं । सारांश: बहुत सावधान रहो के साथ , यहाँ ड्रेगन हो!operator==

ऑपरेटर ओवरलोडिंग एक बहुत शक्तिशाली सिमेंटिक तकनीक है, लेकिन इसका अधिक उपयोग करना आसान है। आदर्श रूप से आपको इसका उपयोग केवल स्थितियों में ही करना चाहिए जब यह संदर्भ से बहुत स्पष्ट हो कि ओवरलोड ऑपरेटर का प्रभाव क्या है। कई मायनों a.union(b)में स्पष्ट है a+b, और की तुलना a*bमें बहुत अधिक अस्पष्ट है a.cartesianProduct(b), खासकर जब से एक कार्टेशियन उत्पाद का परिणाम एक के SetLike<Tuple<T,T>>बजाय होगा SetLike<T>

ऑपरेटर ओवरलोडिंग के साथ वास्तविक समस्याएं तब आती हैं जब एक प्रोग्रामर मानता है कि एक वर्ग एक तरह से व्यवहार करेगा, लेकिन यह वास्तव में दूसरे में व्यवहार करता है। सिमेंटिक क्लैश इस प्रकार है जो मैं सुझा रहा हूं कि इससे बचने की कोशिश करना महत्वपूर्ण है।


1
आप कहते हैं कि मैट्रिसेस पर ऑपरेटर वास्तव में अच्छी तरह से मैप करते हैं, लेकिन मैट्रिक्स गुणन या तो सराहनीय नहीं है। साथ ही प्रतिनिधियों पर ऑपरेटर और भी मजबूत हैं। आप d1 + d2एक ही प्रकार के दो प्रतिनिधियों के लिए कर सकते हैं ।
svick

1
@ मर्क: "डॉट उत्पाद" केवल वैक्टर पर परिभाषित किया गया है; दो मैट्रिक्स को गुणा करना बस "मैट्रिक्स गुणन" कहा जाता है। भेद केवल शब्दार्थ से अधिक है: डॉट उत्पाद एक स्केलर लौटाता है, जबकि मैट्रिक्स-गुणन एक मैट्रिक्स (और, वैसे, गैर-कम्यूटेटिव) देता है
ब्लूराजा - डैनी पफ्लुगुफ्ट

26

मुझे आश्चर्य है कि किसी ने बीसीएल में अधिक दिलचस्प मामलों में से एक का उल्लेख नहीं किया है: DateTimeऔर TimeSpan। आप ऐसा कर सकते हैं:

  • TimeSpanएक और पाने के लिए दो एस जोड़ें या घटाएंTimeSpan
  • TimeSpanएक नकारात्मक पाने के लिए एक पर शून्य से शून्य का उपयोग करेंTimeSpan
  • DateTimeएक पाने के लिए दो एस घटानाTimeSpan
  • TimeSpanएक DateTimeऔर पाने के लिए एक से जोड़ने या घटानाDateTime

ऑपरेटरों कि कर रहे हैं प्रकार का एक बहुत पर समझ बनाने सकता का एक और सेट <, >, <=, >=। बीसीएल में, उदाहरण के Versionलिए उन्हें लागू करता है।


पांडित्य सिद्धांतों के बजाय बहुत वास्तविक उदाहरण!
SIslam

7

पहला उदाहरण जो मेरे दिमाग में आता है, वह बिगइन्टेगर का कार्यान्वयन है , जो आपको बड़े हस्ताक्षरित पूर्णांक के साथ काम करने की अनुमति देता है। MSDN लिंक देखें कि कितने ऑपरेटरों को अधिभारित किया गया है (यानी, एक बड़ी सूची है, और मैंने यह नहीं जांचा कि क्या सभी ऑपरेटरों को अधिभार दिया गया है, लेकिन यह निश्चित रूप से ऐसा लगता है)

इसके अलावा, चूंकि मैं जावा और जावा भी करता हूं, ओवरलोडिंग ऑपरेटरों को अनुमति नहीं देता है, यह लिखने के लिए अविश्वसनीय रूप से मीठा है

BigInteger bi = new BigInteger(0);
bi += 10;

जावा में:

BigDecimal bd = new BigDecimal(0);
bd = bd.add(new BigDecimal(10));

5

मुझे खुशी है कि मैंने इसे देखा क्योंकि मैं विडंबना के साथ बेवकूफ बना रहा हूं और इसमें ऑपरेटर ओवरलोडिंग का एक महान उपयोग है। यहाँ एक नमूना है कि यह क्या कर सकता है।

तो आइरन एक ".NET लैंग्वेज इंप्लीमेंटेशन किट" है और एक पार्सर जनरेटर (LALR पार्सर पैदा करने वाला) है। एक नया वाक्यविन्यास / भाषा सीखने की बजाय पार्सर जनरेटर जैसे कि yacc / lex जैसे आप ऑपरेटर ओवरलोड के साथ C # में व्याकरण लिखते हैं। यहाँ एक सरल बीएनएफ व्याकरण है

// BNF 
Expr := Term | BinExpr
Term := number | ParExpr
ParExpr := "(" + Expr + ")"
BinExpr := number + BinOp + number
BinOp := "+" | "-" | "*" | "/"
number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

तो यह एक साधारण सा व्याकरण है (कृपया इसे बहाना अगर विसंगतियां हैं जैसा कि मैं सिर्फ BNF सीख रहा हूं और व्याकरण का निर्माण कर रहा हूं)। अब C # को देखते हैं:

  var Expr = new NonTerminal("Expr");
  var Term = new NonTerminal("Term");
  var BinExpr = new NonTerminal("BinExpr");
  var ParExpr = new NonTerminal("ParExpr");
  var BinOp = new NonTerminal("BinOp");
  var Statement = new NonTerminal("Statement");
  var ProgramLine = new NonTerminal("ProgramLine");
  var Program = new NonTerminal("Program", typeof(StatementListNode));
  // BNF Rules - Overloading
  Expr.Rule = Term | BinExpr;
  Term.Rule = number | ParExpr;
  ParExpr.Rule = "(" + Expr + ")";
  BinExpr.Rule = Expr + BinOp + Expr;
  BinOp.Rule = ToTerm("+") | "-" | "*" | "/" | "**";

जैसा कि आप देख सकते हैं, ऑपरेटर के ओवरलोडिंग के साथ, C # में व्याकरण लिखना, BNF में लगभग व्याकरण लिखना है। मेरे लिए, यह न केवल समझ में आता है बल्कि ऑपरेटर ओवरलोडिंग का एक बड़ा उपयोग है।


3

प्रमुख उदाहरण ऑपरेटर == / ऑपरेटर! = है।

यदि आप संदर्भ के बजाय डेटा ऑब्जेक्ट्स के साथ दो ऑब्जेक्ट्स की तुलना आसानी से करना चाहते हैं, तो आप ओवरलोड करना चाहते हैं। ईक्वाल्स (और .GashHashCode!), और हो सकता है! = और == ऑपरेटरों के साथ-साथ स्थिरता के लिए भी करना चाहते हों।

मैंने कभी भी C # में अन्य ऑपरेटरों के किसी भी जंगली अधिभार को नहीं देखा है (हालांकि मुझे लगता है कि किनारे के मामले हैं जहां यह उपयोगी हो सकता है)।


1

MSDN का यह उदाहरण दिखाता है कि जटिल संख्याओं को कैसे लागू किया जाए और उन्हें सामान्य + ऑपरेटर का उपयोग किया जाए।

एक अन्य उदाहरण दिखाता है कि इसे मैट्रिक्स के अलावा कैसे करना है, और यह भी बताता है कि गैरेज में कार जोड़ने के लिए इसका उपयोग कैसे करें (लिंक पढ़ें)।


0

अधिभार का अच्छा उपयोग दुर्लभ हो सकता है, लेकिन ऐसा होता है।

ओवरलोडिंग ऑपरेटर == और ऑपरेटर! = विचार के दो स्कूल दिखाते हैं: जो कहने के लिए हैं वे चीजों को आसान बनाते हैं, और यह कहने वालों के खिलाफ पते की तुलना करने से रोकता है (यानी क्या मैं स्मृति में ठीक उसी जगह की ओर इशारा कर रहा हूं, न कि केवल उसी की एक प्रति वस्तु)।

मुझे लगता है कि विशिष्ट परिस्थितियों में काम करने के लिए कास्ट ऑपरेटर ओवरलोड हैं। उदाहरण के लिए, मुझे XML में 0 या 1. के रूप में प्रतिनिधित्व किए गए एक बूलियन को क्रमबद्ध / डिस्क्रिअलाइज़ करना था। बूलियन से इंट और बैक में कास्ट ऑपरेटर (सही या स्पष्ट, मैं भूल गया) ने चाल चली।


4
यह पते की तुलना करने से नहीं रोकता है: आप अभी भी उपयोग कर सकते हैं object.ReferenceEquals()
dan04

@ dan04 जानकर बहुत अच्छा लगा!
MPelletier

पतों की तुलना करने का एक और तरीका यह है कि आप ऑब्जेक्ट के उपयोग को ==कास्टिंग द्वारा मजबूर करें : (object)foo == (object)barहमेशा संदर्भों की तुलना करें। लेकिन मैं ReferenceEquals()@ dan04 उल्लेख के रूप में पसंद करूंगा क्योंकि यह स्पष्ट है कि यह क्या करता है।
svick

0

वे उन चीजों की श्रेणी में नहीं हैं जिन्हें लोग आमतौर पर तब सोचते हैं जब वे ऑपरेटर के ओवरलोडिंग की बात करते हैं, लेकिन मुझे लगता है कि ओवरलोड करने में सक्षम होने के लिए सबसे महत्वपूर्ण ऑपरेटरों में से एक रूपांतरण ऑपरेटर है

रूपांतरण ऑपरेटर विशेष रूप से ऐसे मूल्य प्रकारों के लिए उपयोगी होते हैं जो संख्यात्मक प्रकार के लिए "डी-शुगर" कर सकते हैं, या कुछ संदर्भों में संख्यात्मक प्रकार की तरह कार्य कर सकते हैं। उदाहरण के लिए, आप एक विशेष परिभाषित कर सकता है Idप्रकार है कि एक निश्चित पहचानकर्ता का प्रतिनिधित्व करता है, और आप एक प्रदान कर सकता है निहित करने के लिए रूपांतरण intताकि आप एक पारित कर सकते हैं Idएक तरीका है कि एक लेता है int, लेकिन एक explict से रूपांतरण intकरने के लिए Idइसलिए कोई भी एक पारित कर सकते हैं intएक में वह विधि जो Idपहले बिना ढलाई के होती है।

सी # के बाहर एक उदाहरण के रूप में, पायथन भाषा में कई विशेष व्यवहार शामिल हैं जो ओवरलोडेबल ऑपरेटरों के रूप में कार्यान्वित किए जाते हैं। इनमें inसदस्यता परीक्षण के लिए ()ऑपरेटर, किसी ऑब्जेक्ट को कॉल करने के लिए ऑपरेटर जैसे कि यह एक फ़ंक्शन है, और lenकिसी ऑब्जेक्ट की लंबाई या आकार का निर्धारण करने के लिए ऑपरेटर।

और फिर आपके पास हास्केल, स्काला, और कई अन्य कार्यात्मक भाषाएं हैं, जैसे नाम +सिर्फ साधारण कार्य हैं, और बिल्कुल भी ऑपरेटर नहीं हैं (और इन्फिक्स स्थिति में फ़ंक्शन का उपयोग करने के लिए भाषा समर्थन है)।


0

प्वाइंट Struct में System.Drawing नाम स्थान में दो अलग अलग ऑपरेटर ओवरलोडिंग का उपयोग करके स्थान तुलना करने के लिए अधिक भार का उपयोग करता है।

 Point locationA = new Point( 50, 50 );
 Point locationB = new Point( 50, 50 );

 if ( locationA == locationB )
    Console.WriteLine( "Their locations are the same" );
 else
    Console.WriteLine( "Their locations  are different" );

जैसा कि आप देख सकते हैं, अधिभार का उपयोग करके दो स्थानों के एक्स और वाई सह-निर्देशांक की तुलना करना बहुत आसान है।


0

यदि आप गणितीय वेक्टर से परिचित हैं तो आप +ऑपरेटर को ओवरलोड करने में उपयोग देख सकते हैं । आप एक वेक्टर जोड़ सकता है a=[1,3]के साथ b=[2,-1]और मिल c=[3,2]

बराबरी को ओवरलोड करना (==) एक उपयोगी भी हो सकता है (भले ही यह एक equals()विधि को लागू करने के लिए बेहतर है )। वेक्टर उदाहरण जारी रखने के लिए:

v1=[1,3]
v2=[1,3]
v1==v2 // True

-2

एक फॉर्म पर ड्राइंग के लिए कोड के एक टुकड़े की कल्पना करें

{
  Point p = textBox1.Location;
  Size dp = textBox1.Size;

  // Here the + operator has been overloaded by the CLR
  p += dp;  // Now p points to the lower right corner of the textbox.
  ..
}

एक अन्य आम उदाहरण है जब एक संरचना का उपयोग वेक्टर के रूप में स्थिति की जानकारी रखने के लिए किया जाता है।

public struct Pos
{
    public double x, y, z;
    public double Distance { get { return Math.Sqrt(x * x + y * y + z * z); } }
    public static Pos operator +(Pos A, Pos B)
    {
        return new Pos() { x = A.x + B.x, y = A.y + B.y, z = A.z + B.z };
    }
    public static Pos operator -(Pos A, Pos B)
    {
        return new Pos() { x = A.x - B.x, y = A.y - B.y, z = A.z - B.z };
    }
}

केवल बाद में उपयोग किया जाना है

{
    Pos A = new Pos() { x = 4, y = -1, z = 0.5 };
    Pos B = new Pos() { x = 8, y = 2, z = 1.5 };

    double x = (B - A).Distance;
}

4
आप वैक्टर जोड़ते हैं, स्थिति नहीं: \ _ यह एक अच्छा उदाहरण है कि जब अतिभारित नहीं होना operator+चाहिए (आप वेक्टर के संदर्भ में एक बिंदु को लागू कर सकते हैं, लेकिन आपको दो बिंदुओं को जोड़ने में सक्षम नहीं होना चाहिए)
ब्लूराजा - डैनी पफ्लुगुएफ्ट

@ BlueRaja-DannyPflughoeft: किसी अन्य स्थान की उपज के लिए पदों को जोड़ने का कोई मतलब नहीं है, लेकिन उन्हें घटाना (वेक्टर उत्पादन करना) करता है, जैसा कि उन्हें औसत करता है। एक पी 1, पी 2, पी 3, और पी 4 के माध्यम से औसत गणना कर सकता है p1+((p2-p1)+(p3-p1)+(p4-p1))/4, लेकिन यह कुछ अजीब लगता है।
सुपरकैट

1
Affine ज्यामिति में आप अंक और रेखाओं के साथ बीजगणित कर सकते हैं, जैसे जोड़, स्केलिंग आदि। हालांकि कार्यान्वयन में समरूप निर्देशांक की आवश्यकता होती है, जो आमतौर पर वैसे भी 3 डी ग्राफिक्स में उपयोग किए जाते हैं। दो बिंदुओं का जोड़ वास्तव में उनके औसत के परिणामस्वरूप होता है।
ja72
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.