2010-05-25 13 views
5

यह वह जगह है और अधिक कुछ और की तुलना में एक जिज्ञासा ...सी ++ कक्षाओं के लिए कंपाइलर स्टोर विधियां कहां है?

मान लीजिए इस प्रकार मैं एक सी ++ वर्ग किट्टी है:

class Kitty 
{ 
    void Meow() 
    { 
     //Do stuff 
    } 
} 

किट्टी के प्रत्येक उदाहरण में संकलक जगह() म्याऊ के लिए कोड है?

स्पष्ट रूप से उसी कोड को दोहराने के लिए हर मेमोरी की आवश्यकता होती है। लेकिन दूसरी तरफ, पास के मेमोरी में किसी रिश्तेदार स्थान की शाखाओं के लिए आधुनिक प्रोसेसर पर स्मृति में पूर्ण स्थान की शाखाओं की तुलना में कम असेंबली निर्देशों की आवश्यकता होती है, इसलिए यह संभावित रूप से तेज़ है।

मुझे लगता है कि यह एक कार्यान्वयन विस्तार है, इसलिए विभिन्न कंपाइलर्स अलग-अलग प्रदर्शन कर सकते हैं।

ध्यान रखें, मैं यहां स्थिर या आभासी तरीकों पर विचार नहीं कर रहा हूं।

+0

एक सामान्य प्रश्न के उत्तर के हमले के लिए तैयार हो जाओ (हालांकि +1, यह * एक अच्छा सवाल है :)) .. –

+0

स्पष्टीकरण के लिए, मुझे इनलाइनिंग में रूचि नहीं है। मुझे पता है कि यह कैसे काम करता है। – Mashmagar

उत्तर

3

मेरा मानना ​​है कि उदाहरण विधियों के लिए मानक तरीका किसी भी स्थिर विधि की तरह लागू किया जाना है, केवल 0 बार, लेकिन this पॉइंटर एक विशिष्ट रजिस्टर पर या कॉल करने के लिए ढेर पर पास किया गया है।

1

नहीं, संकलक केवल Meow के लिए कोड उत्पन्न करता है और प्रत्येक Kitty इंस्टेंस का उपयोग करता है, बशर्ते सदस्य को बाहर से संकलित किया गया हो। यदि संकलक फ़ंक्शन को इनलाइन करने में सक्षम होता है और चुनता है तो यह प्रत्येक बिंदु के उपयोग पर डुप्लीकेट हो जाता है (Kitty के प्रत्येक उदाहरण के बजाए)।

4

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

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

+0

यदि मैं आपको सही ढंग से समझता हूं, हुड के तहत यह वह कर रहा है जो पाइथन स्पष्ट रूप से प्रत्येक सदस्य फ़ंक्शन पर करता है, उदाहरण के संदर्भ की आवश्यकता होती है। हाँ? – Mashmagar

+0

किसी भी सदस्य फ़ंक्शन या सदस्य चर का उपयोग करते समय आप whetheer के स्पष्ट रूप से 'इस' सूचक का उपयोग करते हैं, यह हमेशा उपयोग किया जाता है। सदस्य कार्यों के मामले में, इसका मतलब है कि सदस्य कार्य को 'पहले' को अपने पहले (अदृश्य) पैरामीटर के रूप में पास करना है। यदि यह वर्चुअल फ़ंक्शन है, तो वर्चुअल टेबल चीजों को जटिल करता है, लेकिन अनिवार्य रूप से, आप हमेशा 'इस' सूचक को सदस्य कार्यों में अपने पहले पैरामीटर के रूप में पास कर रहे हैं। यही कारण है कि कुछ ऑपरेटर ओवरलोड (जैसे '<< ') को सदस्य कार्यों के बजाय मित्र कार्य होना चाहिए। –

+0

@ मशमगर: हाँ, दोनों काफी समान हैं। –

2

नहीं, यह ऐसा नहीं है जिस तरह से किया जाता है।
virtual नहीं हैं जो तरीके किसी अन्य फ़ंक्शन के समान हैं लेकिन this पॉइंटर के लिए अतिरिक्त तर्क के साथ हैं।

virtualinvoked using a v-table हैं। v-table फ़ंक्शन पॉइंटर्स की एक सूची है जो ऑब्जेक्ट डेटा के बगल में संग्रहीत होती है। एक अर्थ में, यह आपके वर्णन के करीब है लेकिन फिर भी, कार्य के शरीर हमेशा वस्तु के सभी उदाहरणों के लिए समान होते हैं।
यह प्रदर्शित किया जा सकता है यदि आपके पास विधि में static चर है। अलग-अलग उदाहरणों से लागू विधियों के लिए स्थिर चर समान होगा।

+0

दरअसल, अधिकांश कार्यान्वयन ऑब्जेक्ट में vtable पर * सूचक * रखता है और vtable स्वयं ही नहीं। इस सूचक को अक्सर * vptr * कहा जाता है। – fredoverflow

0

कंपाइलर अपनी डेटा संरचना के अंदर प्रत्येक वर्ग (ऑब्जेक्ट नहीं) के लिए एक प्रविष्टि बनाता है। कक्षा के लिए इस प्रविष्टि में उस वर्ग के तरीकों के लिए पॉइंटर्स शामिल हैं।

अभिभावक वर्ग में पॉइंटर के रूप में स्मृति में एक ऑब्जेक्ट का प्रतिनिधित्व किया जाता है और इसके उदाहरण फ़ील्ड का संग्रह होता है (क्योंकि ये प्रत्येक ऑब्जेक्ट के लिए अलग होते हैं।) फिर जब कोई विधि कहलाती है, तो ऑब्जेक्ट पॉइंटर को उसके माता-पिता के पास ले जाता है फिर उचित विधि के लिए सूचक का पालन करें। ऑब्जेक्ट के लिए पॉइंटर विधि को भी प्रदान किया जाता है, जो इस सूचक के रूप में कार्य करता है।

वर्चुअल विधियां थोड़ा अधिक जटिल हैं, लेकिन वे एक ही तरीके से की जाती हैं।

यदि आप और जानना चाहते हैं, तो देखें कि आप प्रोग्रामिंग भाषा कक्षा ले सकते हैं या नहीं।

यहाँ ASCII आर्ट पर एक गरीब प्रयास यह समझाने के लिए है:

obj      class 
+------------+   +----------+ 
| ptrToClass |----------->| method1 | ----------> toSomewhere(ptrToObj) 
|------------|   |----------| 
| field1  |   | method2 | ----------> toSomewhereElse(ptrToObj) 
+------------+   +----------+ 
2

क्योंकि आप वर्ग परिभाषा के अंदर Meow की परिभाषा है, Meow परोक्ष इनलाइन है।

इनलाइन फ़ंक्शन की वास्तविक सामग्री के साथ कॉल को प्रतिस्थापित करने के लिए कंपाइलर का संकेत है। लेकिन यह केवल एक संकेत है - संकलक संकेत को अनदेखा करना चुन सकता है।

यदि संकलक संकेत द्वारा पालन करता है, तो प्रत्येक कॉल फ़ंक्शन सामग्री के साथ प्रतिस्थापित किया जाएगा। इसका मतलब है कि संकलक प्रत्येक बार Meow को फ़ंक्शन कॉल उत्पन्न करने के बजाय कोड जेनरेट करेगा।

यदि संकलक संकेत को अनदेखा करता है, तो कंपाइलर/लिंकर एक एकल संस्करण होने की व्यवस्था करेगा, जिसमें सभी कॉल निर्देशित किए जाएंगे (क्योंकि यह इनलाइन है, एक क्लासिक रणनीति यह है कि फ़ंक्शन का उपयोग करने वाली प्रत्येक अनुवाद इकाई केवल एक संस्करण रखने के लिए लिंकर को निर्देशों के साथ एक अलग प्रति प्राप्त करें)।

आखिरकार, स्पष्टीकरण में जाएं जहां फ़ंक्शन इनलाइन नहीं है। इस मामले में, कोडर के लिए यह सुनिश्चित करना आवश्यक है कि परिभाषा बिल्कुल एक अनुवाद इकाई में दिखाई दे और सभी कॉल इस संस्करण में भेजी जाएंगी।

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