2010-08-31 2 views
5

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

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

अग्रिम धन्यवाद, और यहां हम जाते हैं!

1. कक्षाओं के बीच कनवर्ट करते समय, वास्तव में परिवर्तित होने पर वर्चुअल टेबल होता है।

उदाहरण:

class A{ 
public: 
    A() : x(0) {}; 
    int x; 
    virtual void doStuff() { 
     cout << x <<endl; 
    } 
}; 

class B : public A{ 
public: 
    B() : y(1) {}; 
    int y; 
    virtual void doStuff() { 
     cout << y <<endl; 
    } 
}; 

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

2. कौन-सा मतलब है कि बहुरूपता का लाभ लेने के लिए एक ही रास्ता संकेत और संदर्भ

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

उदाहरण:

void doALotOfStuff(A a1, A a2) { 
    a1.doStuff(); 
    a2.doStuff(); 
} 

int main(){ 
    A a; 
    B b; 
    doALotOfStuff(a,b); 
    return 0; 
} 

प्रिंट आउट होता

0 
0 

क्योंकि संकलक ए में परिवर्तित करने के लिए ख

3. इसके अलावा कोड उत्पन्न होगा, लाभ लेने के लिए एक ही रास्ता सरणी और एसटीएल कंटेनर के साथ इस तरह के बहुरूपता के पॉइंटर्स का उपयोग करना होगा क्योंकि संदर्भों को संग्रहीत नहीं किया जा सकता

क्योंकि संदर्भ आबंटित नहीं हैं के बाद से वेक्टर काम नहीं होता है, यह इस प्रकार है कि अगर मैं आधार वर्ग का एक वेक्टर करना चाहते थे, मैं आदेश के तत्वों में से वर्चुअल टेबल बचाने के लिए एक के संकेत का एक वेक्टर बनाने के लिए की आवश्यकता होगी टाइप बी

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

उत्तर

3

आप बिंदु # 1 में कुछ अच्छा विचार है, वहीं है कि वास्तव में यह कैसे काम करता है। रूपांतरण जगह में नहीं किया जाता है, यह एक नई वस्तु बनाकर किया जाता है जो सदस्यों को प्रतिलिपि बनाता है जो रूपांतरण स्रोत (जिसे कहना है, बेस क्लास के सदस्यों के बारे में है, जब तक कि आपके बेस क्लास में कुछ अजीब आगे की घोषणा न हो)। व्युत्पन्न वस्तु का उदाहरण किसी भी तरह से बदला नहीं जाता है। बेशक प्रतिलिपि मूल वस्तु से एक अलग स्मृति पता है। मूल्य से गुजरने में हमेशा कॉपी करना शामिल है।

+0

आह ठीक है, एक को साफ़ करने के लिए धन्यवाद। – Xzhsh

0

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

बिंदु 1 में आप टाइप बी से ए में 'कनवर्टिंग' के बारे में बात करते हैं। यह थोड़ा उलझन में है क्योंकि यह कहना सही है कि उचित घटकों के साथ एक नई वस्तु बनाई जाएगी। स्लाइसिंग के बारे में अगला बिंदु देखें।

बिंदु 2 में क्या आप प्रदर्शन कर रहे हैं टुकड़ा करने की क्रिया का सिद्धांत है। यह वह जगह है जहां एक व्युत्पन्न वर्ग में व्युत्पन्न भाग हटा दिया गया है और केवल आधार बना हुआ है।

एक बिंदु ध्यान दें कि आप का उपयोग या तो बढ़ावा देने :: shared_ptr या बढ़ावा देने :: अपने एसटीएल कंटेनर में unique_ptr क्योंकि अन्यथा स्मृति प्रबंधन एक खतरनाक सिरदर्द हो जाता है चाहिए।

आप को बढ़ावा देने के बारे में सुना नहीं किया है, तो आप इसे देख सकते हैं here यह एक बहुत ही मूल्यवान संसाधन है।

+0

स्लाइसिंग कुछ भी नहीं हटाती है। व्युत्पन्न वस्तु पूरी तरह बरकरार रहती है। प्रतिलिपि में केवल बेस क्लास के सदस्य शामिल हैं, लेकिन व्युत्पन्न सदस्यों की प्रतिलिपि बनाने की कमी है, उन्हें हटा नहीं रहा है। आप पहले स्थान पर कभी भी अस्तित्व में नहीं आ सकते हैं, और प्रतिलिपि कभी व्युत्पन्न प्रकार नहीं थी। –

3
  1. जब आप कहते हैं कि "A को एक वस्तु कन्वर्ट प्रकार B की b", आप दो अलग बातें मतलब हो सकता है:

    • प्रकार A कि है की नकल कीb से की एक नई वस्तु बनाने, या
    • प्रकार A* का एक सूचक या कि अंक या b को संदर्भित करता है प्रकार A& का संदर्भ लें।

    किसी भी मामले में, मूल वस्तु b अपरिवर्तित है। आप रूपांतरण के बाद इसे फेंक सकते हैं, लेकिन यह एक अलग मुद्दा है, और अकेले रूपांतरण b को परिवर्तित नहीं करता है।

    (दुर्लभ मामलों को छोड़कर जब रूपांतरण ऑपरेटर या निर्माता शामिल B लिए एक गैर स्थिरांक संदर्भ लेता है और तर्क को बदल देता है। हालांकि, यहां तक ​​इस मामले में, यह नहीं vtable प्रतिस्थापन आप उल्लेख किया है।)

    एक बार ऑब्जेक्ट बनने के बाद, इसका प्रकार पूरे जीवनकाल में परिवर्तित नहीं होता है (जब तक इसे नष्ट नहीं किया जाता है)। इसका मतलब है कि आपके द्वारा वर्णित vtable प्रतिस्थापन कभी नहीं होता है।

  2. हां, सी ++ में पॉलिमॉर्फिज्म पॉइंटर्स या संदर्भों के माध्यम से हासिल किया जाता है।

    ध्यान दें कि, आपके उदाहरण में, ए 1 और ए 2 को ए और बी से कॉपी किया गया है, और रूपांतरण किसी भी तरह से या बी को परिवर्तित नहीं करता है।

  3. हाँ, तुम सही हो। या किसी भी तरह का स्मार्ट सूचक स्वीकार्य (या बेहतर) है।

0

आप पास-दर-मूल्य को मिश्रण और पारित-दर-संदर्भ रहे हैं।

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

जब आप पारित-दर-मूल्य, और एक व्युत्पन्न प्रकार पारित करते हैं, वस्तु टुकड़ा करने की क्रिया हो सकता है: http://en.wikipedia.org/wiki/Object_slicing

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

तर्क के लिए, पॉइंटर पास करने से पास-बाय-वैल्यू (आप पॉइंटर की प्रतिलिपि बनाते हैं) के बीच एक संकर है, और पास-बाय-रेफरेंस (आप ऑब्जेक्ट को पॉइंटर संदर्भों की प्रतिलिपि नहीं बनाते हैं)।

इन सबके कारण, पॉलिमॉर्फिज्म (बेस इंटरफ़ेस पर कार्य करने, लेकिन व्युत्पन्न कार्यान्वयन के साथ) करने का एकमात्र तरीका पॉइंटर्स या संदर्भों के माध्यम से होता है।

और हाँ, एसटीएल कंटेनर संदर्भों के साथ काम नहीं कर सकते हैं।

आप Boost से स्मार्ट संकेत का उपयोग संदर्भ की सीमाओं में से कुछ से बचने के लिए कर सकते हैं और "गूंगा" संकेत :)

+0

असल में, बेस कन्स्ट्रक्टर रन के बाद और पहले और उपयोगकर्ता कोड कोड प्राप्त क्लास कन्स्ट्रक्टर चलाने के बाद v-table को प्रतिस्थापित किया जाता है (अवधारणात्मक रूप से कम से कम, और वास्तव में कई मामलों में)। इस समय, उदाहरण का प्रकार वास्तव में बदल गया। विनाश के दौरान यह फिर से होता है। –

+0

@ बेन: आप सही हैं। मुझे लगता है कि बस अपने परिदृश्य में नहीं। इसे –

0

आपका वास्तविक भ्रम बयान 1. वस्तुओं रहे हैं के साथ आता है की उत्तेजना के कुछ से बचने के लिए कभी भी सी ++ में परिवर्तित नहीं होता है - किसी प्रकार का ऑब्जेक्ट हमेशा उस प्रकार का ऑब्जेक्ट होता है (ऑब्जेक्ट के बेस क्लास का निर्माण करते समय कुछ मामूली पीछे-दृश्य दृश्यों को छोड़कर हम बात नहीं करेंगे)। इसके बजाय VALUES परिवर्तित हो जाते हैं, और जब आप एक ऑब्जेक्ट प्रकार से दूसरे ऑब्जेक्ट में कनवर्ट करते हैं, तो वास्तव में क्या हो रहा है कि आप पुराने ऑब्जेक्ट से डेटा के साथ एक नया ऑब्जेक्ट बना रहे हैं।

अपने उदाहरण में 2 के लिए

इसलिए, जब आप doALotOfStuff फोन, संकलक दूसरा तर्क a2 के रूप में पारित करने के लिए एक नया एक बनाने के लिए निर्माता A::A(const B &) कॉल करेंगे। यह a1 के लिए नया ए बनाने के लिए कन्स्ट्रक्टर A::A(const A &) को भी कॉल करेगा, इसलिए a1 और a2a और b से पूरी तरह से अलग ऑब्जेक्ट्स हैं।

+0

ठीक कर देगा, 'कक्षा बी: सार्वजनिक ए' के ​​दौरान एक कन्स्ट्रक्टर 'ए :: ए (कॉन्स बी एंड)' होने के लिए यह बहुत दुर्लभ होगा। सबसे अधिक संभावना है कि सामान्य प्रतिलिपि कन्स्ट्रक्टर 'ए :: ए (कॉन्स ए और)' सबसे अच्छा मिलान होने जा रहा है जब 'बी' प्रकार का मान' doALotOfStuff' को पास किया जाता है। –

+0

@ बेन: सच्चे, लेकिन अप्रासंगिक - ए के लिए निर्माता एक नया ए (और आमतौर पर उनके तर्क को संशोधित नहीं करते हैं) इस पर ध्यान दिए बिना कि वास्तव में कौन से को बुलाया जाता है। –

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