C++ में रिफ्लेक्शन और इंट्रोस्पेक्शन क्या है और इसकी आवश्यकता क्यों है?
\n\nकल्पना करें कि आप एक जटिल गेम इंजन या डेटा प्रोसेसिंग फ्रेमवर्क लिख रहे हैं। किसी बिंदु पर आपको यह समझने की आवश्यकता होती है: "यह ऑब्जेक्ट आखिर क्या है? इसके क्या तरीके हैं? क्या इसके पास name फील्ड है?"
Python या Java जैसी भाषाओं में, यह एक पंक्ति में किया जाता है - वहाँ पूर्ण रिफ्लेक्शन (प्रोग्राम की अपनी संरचना को रनटाइम पर अध्ययन और संशोधित करने की क्षमता) होती है। लेकिन C++ में, यह अधिक जटिल है। C++ एक मजबूत स्टैटिक टाइपिंग वाली भाषा है, और "बॉक्स से बाहर" लगभग कोई रिफ्लेक्शन नहीं है। लेकिन इंट्रोस्पेक्शन है - रनटाइम पर प्रकारों के बारे में जानकारी प्राप्त करने की एक सीमित क्षमता।
\n\nइस लेख में, हम चर्चा करेंगे:
\n- \n
- रिफ्लेक्शन इंट्रोस्पेक्शन से कैसे भिन्न है; \n
- RTTI (Run-Time Type Information) कैसे काम करता है; \n
typeidऔरdynamic_castका उपयोग कैसे करें; \n - टेम्पलेट्स और मैक्रोज़ का उपयोग करके रिफ्लेक्शन का अनुकरण कैसे करें; \n
- आधुनिक विकल्प (C++20/23) और लाइब्रेरीज़। \n
C++ के "लुकिंग ग्लास" में झांकने के लिए तैयार हैं? चलिए शुरू करते हैं!
\n\nइंट्रोस्पेक्शन बनाम रिफ्लेक्शन: क्या अंतर है?
\n\nकोड लिखने से पहले, आइए बिंदुओं को स्पष्ट करें i पर।
\n\n- \n
- इंट्रोस्पेक्शन - यह प्रोग्राम की "खुद को देखने" और प्रकारों के बारे में जानकारी प्राप्त करने की क्षमता है, लेकिन प्रोग्राम की संरचना को बदलना नहीं। उदाहरण के लिए: "किसी ऑब्जेक्ट के वर्ग का नाम जानना"। यह C++ में RTTI के माध्यम से मौजूद है। \n
- रिफ्लेक्शन - यह इंट्रोस्पेक्शन + गतिशील रूप से ऑब्जेक्ट बनाने, विधियों को कॉल करने, फ़ील्ड को संशोधित करने की क्षमता है। C++ में यह मानक में (अभी तक) मौजूद नहीं है। \n
C++ में, हम "रिफ्लेक्शन" शब्द का उपयोग अक्सर एक लक्ष्य के रूप में करते हैं, और "इंट्रोस्पेक्शन" एक उपलब्ध उपकरण के रूप में। लेकिन डरें नहीं: सीमित साधनों के साथ भी, आप शानदार चीजें कर सकते हैं।
\n\nRTTI (Run-Time Type Information) - C++ में इंट्रोस्पेक्शन का आधार
\n\nRTTI एक तंत्र है जो रनटाइम पर किसी ऑब्जेक्ट के प्रकार को निर्धारित करने की अनुमति देता है। यह डिफ़ॉल्ट रूप से सक्षम है (हालांकि कुछ एम्बेडेड सिस्टम में इसे -fno-rtti फ्लैग से अक्षम किया जाता है)।
RTTI के मुख्य खिलाड़ी:
\n- \n
typeid- ऑपरेटर जोstd::type_infoलौटाता है; \n dynamic_cast- पॉलीमॉर्फिक प्रकारों का सुरक्षित रूपांतरण। \n
उदाहरण 1: typeid का उपयोग
\n\n#include <iostream>\n#include <typeinfo>\n\nclass Base { virtual void foo() {} };\nclass Derived : public Base {};\n\nint main() {\n Base* b = new Derived();\n std::cout << "ऑब्जेक्ट का प्रकार: " << typeid(*b).name() << std::endl;\n delete b;\n return 0;\n}\n\nआउटपुट (कंपाइलर पर निर्भर करता है): class Derived या 7Derived (विकृत नाम)।
ध्यान दें: typeid केवल पॉलीमॉर्फिक क्लासेस (कम से कम एक वर्चुअल मेथड वाले) के साथ काम करता है। यदि आप virtual हटाते हैं, तो आपको वास्तविक ऑब्जेक्ट के बजाय पॉइंटर का प्रकार मिलेगा।
उदाहरण 2: dynamic_cast - सुरक्षित रूपांतरण
\n\n#include <iostream>\n\nclass Animal { public: virtual ~Animal() = default; };\nclass Dog : public Animal { public: void bark() { std::cout << "Woof!\\n"; } };\nclass Cat : public Animal { public: void meow() { std::cout << "Meow!\\n"; } };\n\nvoid makeSound(Animal* a) {\n if (Dog* dog = dynamic_cast<Dog*>(a)) {\n dog->bark();\n } else if (Cat* cat = dynamic_cast<Cat*>(a)) {\n cat->meow();\n } else {\n std::cout << "अज्ञात जानवर\\n";\n }\n}\n\nint main() {\n Animal* pets[] = { new Dog(), new Cat(), new Animal() };\n for (auto p : pets) makeSound(p);\n // हटाना न भूलें!\n for (auto p : pets) delete p;\n return 0;\n}\n\nयह इंट्रोस्पेक्शन का एक उत्कृष्ट उदाहरण है: हम नहीं जानते कि वास्तव में कौन सा ऑब्जेक्ट आया है, लेकिन हम