2013-06-11 9 views
15

नीचे सी ++ प्रोग्राम आउटपुट "एसीसीए" क्यों है? operator int() क्यों दो बार बुलाया जाता है?सी ++ ऑपरेटर ओवरलोडिंग

#include "stdafx.h" 
#include <iostream> 

using namespace std; 

class Base { 
public: 
    Base(int m_var=1):i(m_var){ 
     cout<<"A"; 
    } 
    Base(Base& Base){ 
     cout<<"B"; 
     i=Base.i; 
    } 
    operator int() { 
     cout<<"C"; 
     return i; 
    } 
private: 
    int i; 
}; 

int main() 
{ 
    Base obj; 
    obj = obj+obj; 
    return 0; 
} 
+0

एफवाईआई; यह पाठक को एक अभ्यास के रूप में, एसीसीए बनाने के लिए बनाया गया एक निर्माण है। –

उत्तर

30

पहले, इस लाइन:

Base obj; 

डिफ़ॉल्ट-निर्माणों निर्माता कि डिफ़ॉल्ट मान 1 साथ एक पूर्णांक स्वीकार करता है, उठा द्वारा आपत्ति obj। यह मानक आउटपुट पर मुद्रित पहले A के लिए ज़िम्मेदार है।

फिर, इस अभिव्यक्ति:

obj + obj 

operator + के एक व्यवहार्य अधिभार उठा की आवश्यकता है। इस मामले में, obj में int पर उपयोगकर्ता द्वारा परिभाषित रूपांतरण है, अंतर्निहित operator + चुना गया है, और दोनों तर्क int पर परिवर्तित हो गए हैं। यह मानक आउटपुट पर मुद्रित किए जाने वाले दो C के लिए ज़िम्मेदार है।

फिर, में obj असाइनमेंट:

obj = obj + obj 

आह्वान करने के लिए परोक्ष Base के लिए operator = उत्पन्न की जरूरत है। परोक्ष operator = उत्पन्न हस्ताक्षर हैं:

Base& operator = (Base const&); 

इसका मतलब है कि बराबर के चिह्न, प्रकार int की है जो के दाईं ओर अभिव्यक्ति, एक अस्थायी Base वस्तु जहाँ से obj असाइन किया गया है (संदर्भ में परिवर्तित किया जाना चाहिए अंतर्निहित जनरेटेड operator = का पैरामीटर इस अस्थायी से जुड़ा हुआ है)।

लेकिन बदले में एक int से इस अस्थायी के निर्माण Base की परिवर्तित निर्माण है कि एक int फिर से स्वीकार करता है, जो दूसरी A के लिए जिम्मेदार मानक आउटपुट में मुद्रित किया जा रहा है लागू की आवश्यकता है।

9

operator int() दो बार कहा जाता है क्योंकि आप operator+ अतिभारित नहीं किया गया है। संकलक को Base को Base में जोड़ने का तरीका नहीं पता है, इसलिए उन्हें int में परिवर्तित कर दिया गया है (क्योंकि आपने इसे सिखाया है कि यह कैसे करना है), जो यह जानता है कि कैसे करना है। निम्नलिखित कोड प्रिंट ADA:

#include <iostream> 

using namespace std; 

class Base { 
public: 
    Base(int m_var=1):i(m_var){ 
     cout<<"A"; 
    } 
    Base(Base& Base){ 
     cout<<"B"; 
     i=Base.i; 
    } 
    operator int() { 
     cout<<"C"; 
     return i; 
    } 
    int operator+(Base& Base) 
    { 
     cout<<"D"; 
     return i+Base.i; 
    } 
private: 
    int i; 
}; 

int main() 
{ 
    Base obj; 
    obj = obj+obj; 
    return 0; 
} 
1

आप अभिव्यक्ति obj+obj में दो बार obj देखें और ऐसे प्रत्येक संदर्भ एक पूर्णांक के लिए परिवर्तित किया जाना है।

यह असंभव नहीं है (हालांकि यह एक भयानक विचार है) कि ऐसा रूपांतरण "स्टेटफुल" हो सकता है - यानी, यह डिज़ाइन द्वारा हर बार इसे एक अलग मूल्य लौटा सकता है। आखिरकार, obj द्वारा प्रतिनिधित्व किया गया मान बदल सकता है (यह एक काउंटर या ऐसा कुछ हो सकता है)। तो संकलक को प्रत्येक संदर्भ के लिए इसे फिर से मूल्यांकन करना होगा।

+0

चूंकि 'ऑपरेटर int() 'को' const' चिह्नित नहीं किया गया है, इसलिए हस्ताक्षर संकलक को सीधे बताता है कि कॉल को ऑब्जेक्ट की स्थिति को संशोधित करने की अपेक्षा करनी चाहिए। हालांकि यहां तक ​​कि एक कॉन्स ऑपरेटर के लिए, दूसरी कॉल को बिल्कुल अनुकूलित करने की अनुमति नहीं दी जाएगी क्योंकि इसमें कुछ 'cout'' हो सकता है (और यहां, वास्तव में यह है)। – celtschk

+0

और हम एक ऐसे फ़ंक्शन के बारे में सोच सकते हैं जिसमें साइड-इफेक्ट (जैसे मानक आउटपुट को लिखना) है, ब्रह्मांड के एक नए संस्करण को हर बार कॉल करने के रूप में लौटने के रूप में, जो कि "हर बार एक अलग मूल्य लौटने का एक और तरीका है" बुलाया"। –

1

यह प्रति ऑपरेंड में एक बार कॉल किया जाता है, इससे कोई फर्क नहीं पड़ता कि यह वही उदाहरण है।

obj = obj+obj; 

यह एक int के लिए पहला ऑपरेंड "और फिर दूसरा" रहता है।

यदि आप इस निहित कलाकार से बचना चाहते हैं तो आपको ऑपरेटर को अधिभारित करने की आवश्यकता है।

1

यह operator int() दो बार कॉल करता है क्योंकि इसे दोनों को जोड़ने से पहले ओबीजे को int में परिवर्तित करने की आवश्यकता होती है।

5

जब आप वस्तु का निर्माण, तो आपको पहले 'ए' मिलती है:

Base obj; 

जब आप obj+obj जोड़ने के लिए निर्दिष्ट करते हैं, संकलक obj पर + उपयोग करने के लिए एक तरह से यह पता लगाने की जरूरत है। जब से तुम Base के लिए एक operator+ ओवरराइड नहीं किया था, int() करने के लिए रूपांतरण समीकरण के प्रत्येक पक्ष के लिए बुलाया जाता है:

obj+obj 

यह प्रिंट "CC"

उसके बाद, आप obj, प्रकार Base की है जो करने के लिए आवंटित है, तो निर्माता है जो एक पूर्णांक (i + iint() ऑपरेटर से) स्वीकार कर सकते हैं चलाया जाता है, जो प्रिंट 'ए':

obj = obj+obj; // Assignment prints "A" 
5
obj = obj+obj; 
     ^^^--------obj converted to int here 
      ^^^----obj converted to int here 
^^^^^------------Base(int) ctor and default operator= called here 

डाली ऑपरेटरों ओवरलोडिंग जब तक आप लागत को समझते हैं और एक तथ्य यह है कि अपने विशिष्ट मामले में लाभ उन्हें पल्ला झुकना के लिए पता नहीं आम तौर पर एक अच्छा विचार है।

1

पहले एक से

Base obj;

दो सी int को obj+obj में obj परिवर्तित करने के रूप में आप operator + ओवरलोड नहीं था से आते हैं आता है।

अंतिम ए obj = परिणाम int से obj के रूपांतरण से आता है।

2

सी ++ प्रोग्राम नीचे "एसीसीए" की गणना कैसे करता है?

दिखाया गया पहला पत्र 'ए' है। यह आउटपुट इस लाइन से संबंधित है:

Base obj; 

... जिसमें आप बेस का एक नया उदाहरण बना रहे हैं।

अगली पंक्ति थोड़ा जटिल है:

obj = obj+obj; 

आम तौर पर, इस obj.operator+(obj) में अनुवाद किया है, लेकिन आप ऑपरेटर की जरूरत नहीं है + वर्ग Base में अतिभारित है, तो इस अनुवाद मान्य नहीं है। शेष संभावना यह है कि ऑपरेटर + वास्तव में संख्यात्मक जोड़ ऑपरेटर है।

और हाँ, इस के बाद से आप int करने के लिए एक डाली प्रदान की है, संभव है। तो int में समीकरण की प्रत्येक अवधि को परिवर्तित करना संभव है ... और इसलिए operator int को दो बार बुलाया जाता है। वास्तविक समय operator int कहा जाता है जिसे सक्रिय ऑप्टिमाइज़ेशन पर निर्भर करता है। उदाहरण के लिए, कंपाइलर को एहसास हो सकता है कि दोनों शर्तें समान हैं, और फिर operator int को पहली बार कॉल करने के बाद एक नया अस्थायी बनाएं। उस स्थिति में, आप सीसी के बजाय सीए देखेंगे।

अंत में, काम अभिव्यक्ति obj.operator=(temp) निष्पादित किया जाता है। और यहां कीवर्ड temp है। काम करने के लिए defaultoperator= के लिए, क्योंकि यह अधिभारित नहीं है, इसलिए आपको दाईं ओर Base ऑब्जेक्ट होना चाहिए। यह वास्तव में संभव है, क्योंकि Base नए उदाहरण बनाने के लिए int का उपयोग करता है। ठीक है, तो obj + obj का परिणाम एक int (कहते हैं कि यह कहा जाता है 'एक्स') नंबर था, और संकलक, वर्ग Base की एक अस्थायी वस्तु जो संख्या एक्स साथ निर्माण किया है बनाता है के रूप में निम्न पंक्ति मार डाला गया था:

Base temp(x); 

तरह से अंतिम पत्र देखा एक 'ए' है यही कारण है कि। दोबारा, कई कंपाइलर कुछ मामलों पर अस्थायी भवनों से बच सकते हैं, इसलिए अंत में 'ए' नहीं देखना संभव है।

ध्यान दें कि यह पंक्ति:

obj = obj + obj 

इस प्रकार में विघटित था:

int x = ((int) obj) + ((int) obj); 
Base temp(x); 
obj = temp; 

अंतिम शिक्षा का मानो स्मृति जिसमें obj बैठता है की सामग्री के साथ कब्जा कर लिया हो जाएगा परिणाम है temp (यह डिफ़ॉल्ट प्रतिलिपि कन्स्ट्रक्टर की भूमिका है, जो कक्षा के प्रत्येक सदस्य के लिए operator= निष्पादित करती है, फिर से 'तीन का नियम' देखें)।

ऑपरेटर ओवरलोडिंग के मुद्दों है कि हो सकता है अगर आप भाषा के एक कम या ज्यादा गहरा ज्ञान की जरूरत नहीं है अनुमान नहीं कर रहे हैं, जैसा कि आप देख सकते हैं की एक बहुत कुछ शामिल है। इस बात को ध्यान में रखें कि जावा जैसी भाषाएं पूरी तरह से इसका उपयोग रोकती हैं, जबकि सी # इसे नियंत्रित परिप्रेक्ष्य से अनुमति देता है।

संबंधित मुद्दे