C++ फ़ंक्शन के अंत में const का जादू: हुड के नीचे क्या होता है?

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

फ़ंक्शन के अंत में रहस्यमय const: यह क्यों महत्वपूर्ण है?

\n\n

जो कोई भी C++ सीखता है, उसे देर-सबेर int getValue() const; जैसी घोषणाओं का सामना करना पड़ता है। शुरुआती लोगों के लिए यह जादू जैसा लगता है: "const रिटर्न वैल्यू के प्रकार से पहले क्यों नहीं, बल्कि कहीं पीछे क्यों है?"। Stack Overflow पर इस प्रश्न ने सैकड़ों हज़ारों व्यूज़ जुटाए हैं, जिसका मतलब है कि यह कई लोगों को परेशान करता है।

\n\n

आइए एक बार और हमेशा के लिए समझें कि फ़ंक्शन घोषणा के अंत में const का क्या अर्थ है, यह "हुड के नीचे" कैसे काम करता है, और विश्वसनीय कोड लिखने के लिए यह C++ की सबसे उपयोगी सुविधाओं में से एक क्यों है।

\n\n

मूलभूत समझ: अंत में const क्या करता है?

\n\n

जब आप क्लास की सदस्य फ़ंक्शन के पैरामीटर सूची के बाद const लिखते हैं, तो आप कंपाइलर को एक वादा देते हैं:

\n\n
"यह फ़ंक्शन उस ऑब्जेक्ट की स्थिति को नहीं बदलेगा जिसके लिए इसे कॉल किया गया है।"
\n\n

सीधे शब्दों में कहें तो - आप ऐसे फ़ंक्शन के अंदर क्लास के किसी भी नॉन-स्टैटिक फ़ील्ड को बदलने से रोकते हैं (उन फ़ील्ड को छोड़कर जो mutable से चिह्नित हैं, लेकिन इसके बारे में बाद में)।

\n\n

const के बिना उदाहरण

\n
class Player {\npublic:\n    int health;\n    int getHealth() { return health; }\n};
\n\n

सब कुछ काम करता है। लेकिन यदि आप किसी कॉन्स्टेंट ऑब्जेक्ट के लिए getHealth() को कॉल करने का प्रयास करते हैं - तो कंपाइलर एक त्रुटि देगा:

\n\n
const Player p;\nint h = p.getHealth(); // त्रुटि! getHealth() const नहीं है
\n\n

const के साथ उदाहरण

\n
class Player {\npublic:\n    int health;\n    int getHealth() const { return health; } // अंत में const\n};\n\nconst Player p;\nint h = p.getHealth(); // सब ठीक है!
\n\n

अब फ़ंक्शन को किसी भी ऑब्जेक्ट के लिए कॉल किया जा सकता है - चाहे वह कॉन्स्टेंट हो या नॉन-कॉन्स्टेंट।

\n\n

यह हुड के नीचे कैसे काम करता है: अदृश्य this

\n\n

जादू को समझने के लिए, कंपाइलर के अंदर झाँकना होगा। प्रत्येक नॉन-स्टैटिक सदस्य फ़ंक्शन को अंतर्निहित रूप से एक पॉइंटर this प्राप्त होता है। डिफ़ॉल्ट रूप से this का प्रकार होता है:

\n\n
ClassName * const this; // नॉन-कॉन्स्टेंट ऑब्जेक्ट पर कॉन्स्टेंट पॉइंटर
\n\n

जब आप अंत में const जोड़ते हैं, तो this का प्रकार बदल जाता है:

\n\n
const ClassName * const this; // कॉन्स्टेंट ऑब्जेक्ट पर कॉन्स्टेंट पॉइंटर
\n\n

इसका मतलब है कि कंपाइलर स्वचालित रूप से this->field के माध्यम से फ़ील्ड के सभी एक्सेस को const एक्सेस में बदल देता है। किसी फ़ील्ड को बदलने का प्रयास करने पर कंपाइलेशन त्रुटि होगी।

\n\n

उदाहरण: हुड के नीचे क्या है

\n
class Vector2D {\npublic:\n    float x, y;\n    float length() const {\n        // हुड के नीचे: this का प्रकार const Vector2D* है\n        // this->x = 10; // त्रुटि! कॉन्स्टेंट फ़ील्ड को बदला नहीं जा सकता\n        return sqrt(x*x + y*y);\n    }\n};
\n\n

इसकी आवश्यकता क्यों है? तीन मुख्य कारण

\n\n

1. कॉन्स्टेंट करेक्टनेस (const correctness)

\n

यह एक सिद्धांत है जिसमें आप स्पष्ट रूप से बताते हैं कि कौन से फ़ंक्शन ऑब्जेक्ट को बदलते हैं और कौन से नहीं। यह मदद करता है:

\n
    \n
  • डेटा में आकस्मिक बदलाव से बचने में
  • \n
  • कोड को स्व-दस्तावेजीकरण बनाने में
  • \n
  • डीबगिंग को सरल बनाने में
  • \n
\n\n

2. कॉन्स्टेंट रेफरेंस के साथ काम करना

\n

सबसे सामान्य पैटर्न में से एक है ऑब्जेक्ट को कॉन्स्टेंट रेफरेंस द्वारा पास करना। यदि ऑब्जेक्ट में const-मेथड्स नहीं हैं, तो आप उसके साथ काम नहीं कर सकते:

\n\n
void printPlayerInfo(const Player& p) {\n    // const-मेथड्स के बिना यहाँ p.getHealth() को कॉल नहीं किया जा सकता\n    std::cout << p.getHealth(); // const-संस्करण की आवश्यकता है\n}
\n\n

3. const द्वारा ओवरलोडिंग

\n

एक ही फ़ंक्शन के दो संस्करण बनाए जा सकते हैं - कॉन्स्टेंट और नॉन-कॉन्स्टेंट। कंपाइलर संदर्भ के अनुसार उपयुक्त का चयन करेगा:

\n\n
class DataBuffer {\n    char* data;\npublic:\n    char& operator[](size_t index) {\n        return data[index]; // नॉन-कॉन्स्टेंट ऑब्जेक्ट्स के लिए\n    }\n    const char& operator[](size_t index) const {\n                

ब्लॉग

पुस्तक अनुशंसाएँ