सी ++ में एकाधिक विरासत शक्तिशाली है, लेकिन एक मुश्किल उपकरण है, जो अक्सर समस्याओं का कारण बनता है अगर सावधानी से उपयोग नहीं किया जाता है-डायमंड समस्या जैसी समस्याएं।
इस लेख में, हम डायमंड समस्या पर चर्चा करेंगे कि यह कई विरासत से कैसे उत्पन्न होता है, और आप इस मुद्दे को हल करने के लिए क्या कर सकते हैं।
C++ में एकाधिक वंशानुक्रम
एकाधिक वंशानुक्रम है a ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग (OOP) की विशेषता जहां एक उपवर्ग एक से अधिक सुपरक्लास से इनहेरिट कर सकता है। दूसरे शब्दों में, एक बाल वर्ग में एक से अधिक माता-पिता हो सकते हैं।
नीचे दिया गया आंकड़ा कई विरासतों का एक सचित्र प्रतिनिधित्व दिखाता है।
उपरोक्त आरेख में, कक्षा सी है कक्षा तथा कक्षा बी इसके माता-पिता के रूप में।
यदि हम वास्तविक जीवन के परिदृश्य पर विचार करें, तो एक बच्चा अपने पिता और माता से विरासत में मिलता है। तो एक बच्चे को "पिता" और "माँ" के माता-पिता के रूप में एक व्युत्पन्न वर्ग के रूप में दर्शाया जा सकता है। इसी तरह, हमारे पास बहु-विरासत के ऐसे कई वास्तविक जीवन उदाहरण हो सकते हैं।
मल्टीपल इनहेरिटेंस में, इनहेरिट किए गए क्लास के कंस्ट्रक्टर्स को इनहेरिट किए जाने के क्रम में निष्पादित किया जाता है। दूसरी ओर, विनाशकों को उनकी विरासत के विपरीत क्रम में निष्पादित किया जाता है।
आइए अब बहु वंशानुक्रम का वर्णन करें और वस्तुओं के निर्माण और विनाश के क्रम को सत्यापित करें।
एकाधिक वंशानुक्रम का कोड चित्रण
मल्टीपल इनहेरिटेंस इलस्ट्रेशन के लिए, हमने उपरोक्त प्रतिनिधित्व को C++ में बिल्कुल प्रोग्राम किया है। कार्यक्रम के लिए कोड नीचे दिया गया है।
#शामिल
नेमस्पेस एसटीडी का उपयोग करना;
क्लास ए // बेस क्लास ए कंस्ट्रक्टर और डिस्ट्रक्टर के साथ
{
सह लोक:
ए () { cout << "कक्षा ए:: कंस्ट्रक्टर" << एंडल; }
~ए () {कोउट << "कक्षा ए:: डिस्ट्रक्टर" << एंडल; }
};
क्लास बी // बेस क्लास बी कंस्ट्रक्टर और डिस्ट्रक्टर के साथ
{
सह लोक:
बी () { cout << "कक्षा बी:: कंस्ट्रक्टर" << एंडल; }
~बी () {कोउट << "कक्षा बी:: विनाशक" << एंडल; }
};
कक्षा सी: सार्वजनिक बी, सार्वजनिक ए // व्युत्पन्न वर्ग सी वर्ग ए और फिर कक्षा बी विरासत में मिला है (आदेश नोट करें)
{
सह लोक:
सी () { cout << "कक्षा सी:: कंस्ट्रक्टर" << एंडल; }
~सी () {कोउट << "क्लास सी:: डिस्ट्रक्टर" << एंडल; }
};
मुख्य प्रवेश बिंदु(){
सी सी;
वापसी 0;
}
उपरोक्त कार्यक्रम से हमें जो आउटपुट प्राप्त होता है वह इस प्रकार है:
कक्षा बी:: कंस्ट्रक्टर
कक्षा ए:: कंस्ट्रक्टर
क्लास सी:: कंस्ट्रक्टर
कक्षा सी:: विनाशक
कक्षा ए:: विनाशक
कक्षा बी:: विनाशक
अब अगर हम आउटपुट की जांच करते हैं, तो हम देखते हैं कि कंस्ट्रक्टर्स को B, A और C क्रम में बुलाया जाता है जबकि डिस्ट्रक्टर्स उल्टे क्रम में होते हैं। अब जब हम बहु वंशानुक्रम की मूल बातें जानते हैं, तो हम हीरे की समस्या पर चर्चा करने के लिए आगे बढ़ते हैं।
हीरा समस्या, समझाया
डायमंड प्रॉब्लम तब होती है जब एक चाइल्ड क्लास दो पैरेंट क्लास से इनहेरिट करती है जो दोनों एक ही ग्रैंडपैरेंट क्लास शेयर करते हैं। यह नीचे दिए गए चित्र में दिखाया गया है:
यहाँ, हमारे पास एक वर्ग है बच्चा वर्गों से विरासत में मिला पिता तथा मां. ये दो वर्ग, बदले में, वर्ग का वारिस करते हैं व्यक्ति क्योंकि पिता और माता दोनों व्यक्ति हैं।
जैसा कि चित्र में दिखाया गया है, क्लास चाइल्ड को क्लास पर्सन के लक्षण दो बार विरासत में मिलते हैं - एक बार पिता से और फिर माँ से। यह अस्पष्टता को जन्म देता है क्योंकि संकलक यह समझने में विफल रहता है कि किस रास्ते पर जाना है।
यह परिदृश्य हीरे के आकार के वंशानुक्रम ग्राफ को जन्म देता है और इसे "द डायमंड प्रॉब्लम" कहा जाता है।
डायमंड समस्या का कोड चित्रण
नीचे हमने प्रोग्रामेटिक रूप से हीरे के आकार की विरासत के उपरोक्त उदाहरण का प्रतिनिधित्व किया है। कोड नीचे दिया गया है:
#शामिल
नेमस्पेस एसटीडी का उपयोग करना;
वर्ग व्यक्ति {// वर्ग व्यक्ति
सह लोक:
व्यक्ति (int x) { cout << "व्यक्ति:: व्यक्ति (int) कहा जाता है" << endl; }
};
वर्ग पिता: सार्वजनिक व्यक्ति {// वर्ग पिता व्यक्ति को विरासत में मिला है
सह लोक:
पिता (int x): व्यक्ति (x) {
cout << "पिता:: पिता (int) कहा जाता है" << endl;
}
};
क्लास मदर: पब्लिक पर्सन {// क्लास मदर इनहेरिट पर्सन
सह लोक:
माता (int x): व्यक्ति (x) {
cout << "माँ:: माँ (int) कहा जाता है" << endl;
}
};
क्लास चाइल्ड: पब्लिक फादर, पब्लिक मदर {// चाइल्ड वारिस फादर एंड मदर
सह लोक:
बच्चा (int x): माता (x), पिता (x) {
cout << "चाइल्ड:: चाइल्ड (इंट) कॉल" << एंडल;
}
};
मुख्य प्रवेश बिंदु() {
बच्चा बच्चा (30);
}
इस कार्यक्रम का आउटपुट निम्नलिखित है:
व्यक्ति:: व्यक्ति (int) कहा जाता है
पिता:: पिता (इंट) ने बुलाया
व्यक्ति:: व्यक्ति (int) कहा जाता है
माँ:: माँ (इंट) बुलाया
बच्चा:: बच्चा (int) कहा जाता है
अब आप यहां अस्पष्टता देख सकते हैं। पर्सन क्लास कंस्ट्रक्टर को दो बार कहा जाता है: एक बार जब फादर क्लास ऑब्जेक्ट बनाया जाता है और अगला जब मदर क्लास ऑब्जेक्ट बनाया जाता है। अस्पष्टता को जन्म देते हुए व्यक्ति वर्ग के गुण दो बार विरासत में मिले हैं।
चूँकि पर्सन क्लास कंस्ट्रक्टर को दो बार बुलाया जाता है, चाइल्ड क्लास ऑब्जेक्ट के नष्ट होने पर डिस्ट्रक्टर को भी दो बार बुलाया जाएगा।
अब यदि आप समस्या को सही ढंग से समझ गए हैं, तो आइए हीरे की समस्या के समाधान पर चर्चा करें।
C++ में डायमंड प्रॉब्लम को कैसे ठीक करें?
हीरे की समस्या का समाधान है आभासी खोजशब्द। हम दो अभिभावक वर्ग (जो एक ही दादा-दादी वर्ग से विरासत में मिले हैं) को आभासी कक्षाओं में बनाते हैं ताकि बच्चे की कक्षा में दादा-दादी वर्ग की दो प्रतियों से बचा जा सके।
आइए उपरोक्त चित्रण को बदलें और आउटपुट की जांच करें:
डायमंड समस्या को ठीक करने के लिए कोड चित्रण
#शामिल
नेमस्पेस एसटीडी का उपयोग करना;
वर्ग व्यक्ति {// वर्ग व्यक्ति
सह लोक:
व्यक्ति () { cout << "व्यक्ति:: व्यक्ति () कहा जाता है" << endl; } // बेस कंस्ट्रक्टर
व्यक्ति (int x) { cout << "व्यक्ति:: व्यक्ति (int) कहा जाता है" << endl; }
};
क्लास फादर: वर्चुअल पब्लिक पर्सन {// क्लास फादर को पर्सन विरासत में मिलता है
सह लोक:
पिता (int x): व्यक्ति (x) {
cout << "पिता:: पिता (int) कहा जाता है" << endl;
}
};
क्लास मदर: वर्चुअल पब्लिक पर्सन {// क्लास मदर इनहेरिट पर्सन
सह लोक:
माता (int x): व्यक्ति (x) {
cout << "माँ:: माँ (int) कहा जाता है" << endl;
}
};
क्लास चाइल्ड: पब्लिक फादर, पब्लिक मदर {// क्लास चाइल्ड वारिस फादर एंड मदर
सह लोक:
बच्चा (int x): माता (x), पिता (x) {
cout << "चाइल्ड:: चाइल्ड (इंट) कॉल" << एंडल;
}
};
मुख्य प्रवेश बिंदु() {
बच्चा बच्चा (30);
}
यहां हमने का उपयोग किया है आभासी कीवर्ड जब वर्ग पिता और माता व्यक्ति वर्ग को विरासत में लेते हैं। इसे आमतौर पर "वर्चुअल इनहेरिटेंस" कहा जाता है, जो गारंटी देता है कि विरासत में मिले वर्ग (इस मामले में, व्यक्ति वर्ग) का केवल एक ही उदाहरण पारित किया जाता है।
दूसरे शब्दों में, चाइल्ड क्लास में व्यक्ति वर्ग का एक ही उदाहरण होगा, जिसे पिता और माता दोनों वर्गों द्वारा साझा किया जाएगा। व्यक्ति वर्ग का एकल उदाहरण होने से अस्पष्टता का समाधान हो जाता है।
उपरोक्त कोड का आउटपुट नीचे दिया गया है:
व्यक्ति:: व्यक्ति () कहा जाता है
पिता:: पिता (इंट) ने बुलाया
माँ:: माँ (इंट) बुलाया
बच्चा:: बच्चा (int) कहा जाता है
यहां आप देख सकते हैं कि क्लास पर्सन कंस्ट्रक्टर को केवल एक बार बुलाया जाता है।
वर्चुअल इनहेरिटेंस के बारे में ध्यान देने वाली एक बात यह है कि भले ही इसका पैरामीटराइज्ड कंस्ट्रक्टर हो व्यक्ति वर्ग को स्पष्ट रूप से पिता और माता वर्ग के रचनाकारों द्वारा आरंभीकरण के माध्यम से बुलाया जाता है सूचियाँ, केवल व्यक्ति वर्ग का मूल निर्माता कहा जाएगा.
ऐसा इसलिए है क्योंकि वर्चुअल बेस क्लास का केवल एक ही उदाहरण है जिसे कई वर्गों द्वारा साझा किया जाता है जो इससे प्राप्त होते हैं।
बेस कंस्ट्रक्टर को कई बार चलने से रोकने के लिए, वर्चुअल बेस क्लास के कंस्ट्रक्टर को इससे इनहेरिट करने वाले क्लास द्वारा नहीं कहा जाता है। इसके बजाय, कंस्ट्रक्टर को कंक्रीट क्लास के कंस्ट्रक्टर द्वारा बुलाया जाता है।
ऊपर के उदाहरण में, क्लास चाइल्ड सीधे क्लास पर्सन के लिए बेस कंस्ट्रक्टर को कॉल करता है।
सम्बंधित: C++ में मानक टेम्पलेट लाइब्रेरी के लिए एक शुरुआती मार्गदर्शिका
क्या होगा यदि आपको बेस क्लास के पैरामीटरयुक्त कंस्ट्रक्टर को निष्पादित करने की आवश्यकता है? आप इसे पिता या माता की कक्षाओं के बजाय बाल वर्ग में स्पष्ट रूप से बुलाकर ऐसा कर सकते हैं।
C++ में डायमंड प्रॉब्लम, सॉल्व्ड
डायमंड प्रॉब्लम एक अस्पष्टता है जो कई वंशानुक्रम में उत्पन्न होती है जब दो अभिभावक वर्ग एक ही दादा-दादी वर्ग से विरासत में मिलते हैं, और दोनों मूल वर्ग एक ही बच्चे वर्ग द्वारा विरासत में मिलते हैं। वर्चुअल इनहेरिटेंस का उपयोग किए बिना, चाइल्ड क्लास दादा-दादी वर्ग के गुणों को दो बार इनहेरिट करेगा, जिससे अस्पष्टता होगी।
यह वास्तविक दुनिया के कोड में अक्सर क्रॉप हो सकता है, इसलिए जब भी यह देखा जाए तो उस अस्पष्टता को संबोधित करना महत्वपूर्ण है।
वर्चुअल इनहेरिटेंस का उपयोग करके डायमंड प्रॉब्लम को ठीक किया जाता है, जिसमें आभासी कीवर्ड का उपयोग तब किया जाता है जब माता-पिता वर्ग साझा दादा-दादी वर्ग से प्राप्त होते हैं। ऐसा करने से दादा-दादी वर्ग की केवल एक प्रति बनाई जाती है, और दादा-दादी वर्ग का वस्तु निर्माण बाल वर्ग द्वारा किया जाता है।
प्रोग्रामिंग सीखना चाहते हैं लेकिन यह नहीं जानते कि कहां से शुरू करें? ये शुरुआती प्रोग्रामिंग प्रोजेक्ट और ट्यूटोरियल आपको शुरू कर देंगे।
आगे पढ़िए
- प्रोग्रामिंग
- सी प्रोग्रामिंग
हमारे न्यूज़लेटर की सदस्यता लें
तकनीकी युक्तियों, समीक्षाओं, निःशुल्क ई-पुस्तकों और अनन्य सौदों के लिए हमारे न्यूज़लेटर से जुड़ें!
सब्सक्राइब करने के लिए यहां क्लिक करें