c++ - फ़ंक्शन पॉइंटर परिभाषाएं एम्पर्सेंड 'और' या तारांकन '*' के साथ काम क्यों करती हैं?




function-pointers (2)

इसमें कुछ टुकड़े हैं जो ऑपरेटर के इन सभी संयोजनों को उसी तरह काम करने की अनुमति देते हैं।

मौलिक कारण यह है कि इन सभी कार्यों में यह है कि एक फ़ंक्शन (जैसे foo ) फ़ंक्शन में सूचक के लिए पूरी तरह से परिवर्तनीय है। यही कारण है कि void (*p1_foo)() = foo; काम करता है: foo पूरी तरह से एक सूचक में परिवर्तित कर दिया जाता है और वह सूचक p1_foo को सौंपा जाता है।

यूनरी & , जब किसी फ़ंक्शन पर लागू होता है, तो फ़ंक्शन में पॉइंटर उत्पन्न करता है, जैसे किसी ऑब्जेक्ट पर लागू होने पर ऑब्जेक्ट का पता उत्पन्न होता है। सामान्य कार्यों के लिए पॉइंटर्स के लिए, अंतर्निहित फ़ंक्शन-टू-फ़ंक्शन-पॉइंटर रूपांतरण की वजह से यह हमेशा अनावश्यक होता है। किसी भी मामले में, यही कारण है कि void (*p3_foo)() = &foo; काम करता है।

यूनरी * , जब फ़ंक्शन पॉइंटर पर लागू होता है, तो पॉइंट-टू फ़ंक्शन उत्पन्न करता है, जैसे कि यह किसी ऑब्जेक्ट को सामान्य पॉइंटर पर लागू होने पर इंगित करने वाली ऑब्जेक्ट उत्पन्न करता है।

इन नियमों को जोड़ा जा सकता है। अंतिम उदाहरण के लिए अपने दूसरे पर विचार करें, **foo :

  • सबसे पहले, foo पूरी तरह से एक पॉइंटर में परिवर्तित कर दिया जाता है और पहला * उस फ़ंक्शन पॉइंटर पर लागू होता है, जो फ़ंक्शन को फिर से प्रस्तुत करता है।
  • फिर, नतीजा फिर से एक सूचक को अपने आप में परिवर्तित कर दिया जाता है और दूसरा * लागू होता है, फिर फ़ंक्शन foo
  • इसके बाद यह फिर से एक फ़ंक्शन पॉइंटर में परिवर्तित हो जाता है और चर को आवंटित किया जाता है।

आप जितनी चाहें उतनी * जोड़ सकते हैं, नतीजा हमेशा एक जैसा होता है। अधिक * एस, मर्फी।

हम आपके पांचवें उदाहरण पर भी विचार कर सकते हैं, &*foo :

  • सबसे पहले, foo पूरी तरह से एक सूचक में परिवर्तित कर दिया गया है; यूनरी * लागू किया जाता है, फिर से foo उपज।
  • फिर, foo लागू होता है, जो foo को पॉइंटर प्रदान करता है, जो चर को आवंटित किया जाता है।

केवल एक फ़ंक्शन पर लागू किया जा सकता है, हालांकि फ़ंक्शन पॉइंटर में परिवर्तित किए गए फ़ंक्शन के लिए नहीं (जब तक, निश्चित रूप से, फ़ंक्शन पॉइंटर एक चर नहीं है, जिस स्थिति में परिणाम पॉइंटर-टू-ए-पॉइंटर होता है -एक-फ़ंक्शन; उदाहरण के लिए, आप अपनी सूची void (**pp_foo)() = &p7_foo; ) में जोड़ सकते हैं।

यही कारण है कि &&foo काम नहीं करता है: &foo कोई फ़ंक्शन नहीं है; यह एक फ़ंक्शन पॉइंटर है जो एक रावल्यू है। हालांकि, &*&*&*&*&*&*foo काम करेगा, जैसा कि &******&foo , क्योंकि उन दोनों अभिव्यक्तियों में हमेशा एक फ़ंक्शन पर लागू होता है, न कि एक रावल्यू फ़ंक्शन पॉइंटर ।

ध्यान दें कि फ़ंक्शन पॉइंटर के माध्यम से कॉल करने के लिए आपको यूनरी * का उपयोग करने की आवश्यकता नहीं है; दोनों (*p1_foo)(); और (p1_foo)(); फ़ंक्शन-टू-फ़ंक्शन-पॉइंटर रूपांतरण की वजह से एक ही परिणाम है।

निम्नलिखित काम क्यों करते हैं?

void foo() {
    cout << "Foo to you too!\n";
};

int main() {
    void (*p1_foo)() = foo;
    void (*p2_foo)() = *foo;
    void (*p3_foo)() = &foo;
    void (*p4_foo)() = *&foo;
    void (*p5_foo)() = &*foo;
    void (*p6_foo)() = **foo;
    void (*p7_foo)() = **********************foo;

    (*p1_foo)();
    (*p2_foo)();
    (*p3_foo)();
    (*p4_foo)();
    (*p5_foo)();
    (*p6_foo)();
    (*p7_foo)();
}

मुझे लगता है कि यह याद रखना भी सहायक है कि सी अंतर्निहित मशीन के लिए सिर्फ एक अमूर्त है और यह उन स्थानों में से एक है जहां अमूर्तता लीक हो रही है।

कंप्यूटर के परिप्रेक्ष्य से, एक फ़ंक्शन केवल एक स्मृति पता होता है, जिसे निष्पादित किया जाता है, अन्य निर्देश करता है। इसलिए सी में एक फ़ंक्शन को स्वयं एक पते के रूप में मॉडलिंग किया जाता है, जो संभवतः उस डिज़ाइन की ओर जाता है जो एक फ़ंक्शन "जैसा ही होता है" जैसा पता चलता है।





function-pointers