54

रूपांतरण ऑपरेटर और रचनाकारों के बारे में SO पर कुछ प्रश्नों को पढ़ना मुझे उन दोनों के बीच बातचीत के बारे में सोचने लगा, अर्थात् जब 'अस्पष्ट' कॉल होता है। निम्नलिखित कोड पर विचार करें:रूपांतरण कन्स्ट्रक्टर बनाम रूपांतरण ऑपरेटर: प्राथमिकता

class A; 

class B { 
     public: 
     B(){} 

     B(const A&) //conversion constructor 
     { 
       cout << "called B's conversion constructor" << endl; 
     } 
}; 

class A { 
     public: 
     operator B() //conversion operator 
     { 
       cout << "called A's conversion operator" << endl; 
       return B(); 
     } 
}; 

int main() 
{ 
    B b = A(); //what should be called here? apparently, A::operator B() 
    return 0; 
} 

ऊपर कोड प्रदर्शित करता है "एक के रूपांतरण ऑपरेटर कहा जाता है", जिसका अर्थ है कि रूपांतरण ऑपरेटर के रूप में निर्माता के लिए विरोध किया कहा जाता है। यदि आप A से operator B() कोड को हटा/टिप्पणी करते हैं, तो संकलक इसके बजाय कन्स्ट्रक्टर का उपयोग करने के लिए खुशी से स्विच करेगा (कोड में कोई अन्य परिवर्तन नहीं)।

मेरे प्रश्न हैं:

  1. के बाद से संकलक पर विचार नहीं करता B b = A(); एक अस्पष्ट कॉल होने के लिए, यहाँ काम पर पूर्वता के कुछ प्रकार होना चाहिए। यह प्राथमिकता कहां स्थापित की गई है? (सी ++ मानक से एक संदर्भ/उद्धरण की सराहना की जाएगी)
  2. किसी ऑब्जेक्ट-ओरिएंटेड दार्शनिक दृष्टिकोण से, क्या इस तरह कोड को व्यवहार करना चाहिए? A ऑब्जेक्ट B ऑब्जेक्ट, A या B कैसे बनना चाहिए इस बारे में और कौन जानता है? सी ++ के अनुसार, उत्तर A है - क्या वस्तु-उन्मुख अभ्यास में कुछ भी है जो सुझाव देता है कि यह मामला होना चाहिए? मेरे लिए व्यक्तिगत रूप से, यह किसी भी तरह से समझ में आता है, इसलिए मुझे यह जानने में दिलचस्पी है कि चुनाव कैसे बनाया गया था।

अग्रिम

+0

लाइन आप टिप्पणी की "// कॉपी निर्माता" एक प्रति निर्माता, यह एक निर्माता है नहीं है: शायद यह है, क्योंकि निम्न कोड अभी भी बी के निर्माता कॉल temporaries के लिए कुछ विशेष व्यवहार है। –

+0

आप सही हैं, मैंने इस शब्द का दुरुपयोग किया। मैंने इसे संपादित कर लिया है। – GRB

उत्तर

42

आप प्रारंभ कॉपी कर सकता हूँ धन्यवाद, और उम्मीदवार कार्यों कि रूपांतरण अनुक्रम में रूपांतरण करने के लिए माना जाता है रूपांतरण कार्यों और परिवर्तित निर्माता ये हैं। ये आपके मामले में हैं

B(const A&) 
operator B() 

अब, जिस तरह से आप उन्हें घोषित करते हैं। ओवरलोड रिज़ॉल्यूशन उस से दूर है, और प्रत्येक उम्मीदवार को कॉलम के तर्कों के अनुरूप पैरामीटर की सूची में बदल देता है। पैरामीटर

B(const A&) 
B(A&) 

दूसरा ऐसा इसलिए है क्योंकि रूपांतरण फ़ंक्शन एक सदस्य कार्य है। A& तथाकथित अंतर्निहित ऑब्जेक्ट पैरामीटर है जो एक उम्मीदवार सदस्य कार्य करते समय उत्पन्न होता है। अब, तर्क A टाइप किया गया है। निहित ऑब्जेक्ट पैरामीटर को बाध्य करते समय, एक गैर-कॉन्स्ट संदर्भ एक रावल्यू से बांध सकता है। तो, एक और नियम कहता है कि जब आपके पास दो व्यावहारिक कार्य होते हैं जिनके पैरामीटर संदर्भ हैं, तो उम्मीदवार कम से कम कॉन्स्ट क्वालिफिकेशन जीतेंगे। यही कारण है कि आपका रूपांतरण फ़ंक्शन जीतता है। operator B एक कॉन्स सदस्य फ़ंक्शन बनाने का प्रयास करें। आप एक अस्पष्टता देखेंगे।

किसी ऑब्जेक्ट-उन्मुख दार्शनिक दृष्टिकोण से, क्या इस तरह कोड को व्यवहार करना चाहिए? ए ऑब्जेक्ट को बी ऑब्जेक्ट, ए या बी कैसे बनना चाहिए, इस बारे में और कौन जानता है? सी ++ के मुताबिक, जवाब ए है - क्या वस्तु-उन्मुख अभ्यास में कुछ भी है जो बताता है कि यह मामला होना चाहिए? मेरे लिए व्यक्तिगत रूप से, यह किसी भी तरह से समझ में आता है, इसलिए मुझे यह जानने में दिलचस्पी है कि चुनाव कैसे बनाया गया था।

रिकॉर्ड के लिए, यदि आप रूपांतरण समारोह एक स्थिरांक सदस्य कार्य करना है, तो जीसीसी निर्माता चुना जाएगा (ताकि जीसीसी कि B इसके साथ और अधिक व्यापार है लगता है लगता है?)। इसे डायग्नोस्टिक बनाने के लिए पैडेंटिक मोड (-pedantic) पर स्विच करें।


Standardese, 8.5/14

अन्यथा (यानी, शेष कॉपी-प्रारंभ मामलों के लिए), उपयोगकर्ता परिभाषित रूपांतरण दृश्यों कि स्रोत प्रकार से गंतव्य प्रकार में बदलने या सकता है (जब एक रूपांतरण फ़ंक्शन का उपयोग किया जाता है) इसके व्युत्पन्न वर्ग में 13.3.1.4 में वर्णित अनुसार वर्णित किया गया है, और सबसे अच्छा अधिभार संकल्प (13.3) के माध्यम से चुना जाता है।

और 13.3.1.4

अधिभार संकल्प उपयोगकर्ता परिभाषित रूपांतरण लागू किया जा करने के लिए चयन करने के लिए प्रयोग किया जाता है।

  • परिवर्तित कंस्ट्रक्टर्स टी की (12.3.1) के उम्मीदवार कार्य हैं: यह मानते हुए कि "CV1 टी" वस्तु के प्रकार के टी एक वर्ग के प्रकार के साथ, प्रारंभ किया जा रहा है, उम्मीदवार कार्यों के रूप में निम्नानुसार चुने गए हैं।
  • जब प्रारंभकर्ता अभिव्यक्ति का प्रकार एक वर्ग प्रकार "सीवी एस" है, तो एस और उसके मूल वर्गों के रूपांतरण कार्यों पर विचार किया जाता है। जो एस के भीतर छिपे नहीं हैं और एक प्रकार का उपज करते हैं जिसका सीवी-अयोग्य संस्करण टी के समान प्रकार है या इसके व्युत्पन्न वर्ग के उम्मीदवार कार्य हैं। रूपांतरण फ़ंक्शन जो "एक्स के संदर्भ में" संदर्भ X को वापस लौटाते हैं और इसलिए उम्मीदवार कार्यों को चुनने की इस प्रक्रिया के लिए एक्स उत्पन्न करने के लिए माना जाता है।

दोनों मामलों में, तर्क सूची में एक तर्क है, जो प्रारंभकर्ता अभिव्यक्ति है। [नोट: इस तर्क की तुलना रचनाकारों के पहले पैरामीटर और रूपांतरण कार्यों के निहित ऑब्जेक्ट पैरामीटर के विरुद्ध की जाएगी। ]

और 13.3.3.2/3

  • स्टैंडर्ड रूपांतरण अनुक्रम एस 1 मानक रूपांतरण अनुक्रम एस 2 की तुलना में एक बेहतर रूपांतरण अनुक्रम है अगर [...] एस 1 और एस 2 संदर्भ बाइंडिंग (8.5.3), और जिन संदर्भों के संदर्भ संदर्भ संदर्भ हैं वे शीर्ष-स्तर के सीवी-क्वालीफायर को छोड़कर समान प्रकार हैं, और जिस प्रकार से एस 2 द्वारा प्रारंभ किया गया संदर्भ संदर्भित करता है, उस प्रकार से अधिक सीवी-योग्यता है जिस पर एस 1 द्वारा प्रारंभिक संदर्भ संदर्भित होता है।
+1

आह, इसलिए मेरी समस्या कन्स्ट्रक्टर और ऑपरेटर के बीच प्राथमिकता के बारे में नहीं थी, बल्कि प्रत्येक का 'कॉन्स्ट'स' था। आप सही थे, 'ऑपरेटर बी() '' ऑपरेटर बी() const' में बदलकर 'अस्पष्टता त्रुटि हुई। – GRB

+1

क्या एक संयोग है कि मैंने पहले एक उदाहरण के रूप में मेरा एक और जवाब पर "विश्लेषण" रखा है: http://stackoverflow.com/questions/1051379/is-there-a-difference-in-c-between-copy- प्रारंभिक-और-असाइनमेंट-प्रारंभिक/1051468 # 1051468 xD –

+0

उत्तर की पहली वाक्य के बारे में त्वरित प्रश्न - 'आप प्रारंभिक प्रतिलिपि बनाते हैं ...'। मुझे कहीं भी एक प्रतिलिपि नहीं दिखाई दे रही है - यानी, 'ए'' से कोई 'ए' नहीं बनाया जा रहा है (न ही 'बी' किसी अन्य 'बी' से) - तो क्या मैं सही हूं कि आपको सचमुच 'प्रतिलिपि' नहीं है प्रारंभिकरण ', बल्कि 'असाइनमेंट प्रारंभिकरण' के आधार पर कुछ? धन्यवाद! –

3

ऐसा लगता है MSVS2008 निर्माता चयन के बारे में अपनी ही राय है: यह बी में प्रतिलिपि निर्माता परवाह किए बिना कॉल एक के ऑपरेटर की constness की। इसलिए मानक सावधानी बरतने के बावजूद यहां सावधान रहें।

मैंने सोचा कि एमएसवीएस रूपांतरण ऑपरेटर से पहले उपयुक्त कन्स्ट्रक्टर की तलाश में है, लेकिन फिर पाया कि यह ए के ऑपरेटर बी() को कॉल करना शुरू कर देता है यदि आप बी के कन्स्ट्रक्टर से कॉन्स शब्द निकालते हैं।

A a; 

B b = a;