दिलचस्प पोस्ट
IPhone xib को iPad xib में परिवर्तित करना? हम लॉगरर्स को स्थिर फाइनल क्यों घोषित करते हैं? सीएसएस का प्रयोग करके घुमावदार किनारे षट्भुज कैसे बनायें एंड्रॉइड एसडीके उपकरण संशोधन 22 मुद्दा? टेक्स्टव्यू शैली सेट करें (बोल्ड या इटैलिक) क्या मैं जीवनकाल का उपयोग कर जंग स्ट्रैक्ट्स बनाने के लिए करता हूं जो कि एक-दूसरे को चक्रीय रूप से संदर्भित करते हैं? IE में <select> नहीं फ़ायरिंग में jQuery परिवर्तन ईवेंट सी # का उपयोग करते हुए वर्षों में अंतर अंतर सीएसएस: चयनित छद्म वर्ग की तरह: जाँच की, लेकिन <select> तत्वों के लिए एक्सटेंशन के तरीकों को एक गैर-सामान्य स्थिर वर्ग में परिभाषित किया जाना चाहिए IE का पता लगाने के लिए Modernizr का उपयोग करने के लिए सही तरीका है? समूह युग्नेट परीक्षण व्यू स्पेस गहराई मूल्य और एनएनडीसी xy को देखते हुए रिक्त स्थान को कैसे ठीक किया जाए ए के एजेक्स टैग की घटना विशेषता को मैं कौन सा मान कर सकता हूं? एचटीएमएल 5 का उपयोग करते हुए, मैं एक फॉर्म सबमिशन में कंटेट करने योग्य फ़ील्ड का उपयोग कैसे करूं?

एकाधिक विरासत के साथ सटीक समस्या क्या है?

मैं लोगों को हर समय पूछ रहा हूं कि बहु भाग को सी # या जावा के अगले संस्करण में शामिल किया जाना चाहिए। सी ++ लोग, जो इस क्षमता के लिए बहुत भाग्यशाली हैं, कहते हैं कि यह किसी को रस्सी देने के लिए अंततः अपने आप को लटका देने जैसा है।

एकाधिक विरासत के साथ क्या बात है? क्या कोई ठोस नमूने हैं?

Solutions Collecting From Web of "एकाधिक विरासत के साथ सटीक समस्या क्या है?"

सबसे स्पष्ट समस्या समारोह ओवरराइड के साथ है

मान लीजिए कि दो कक्षाएं ए और बी हैं, दोनों ही एक विधि "doSomething" परिभाषित करते हैं अब आप एक तीसरे वर्ग सी को परिभाषित करते हैं, जो कि ए और बी दोनों से प्राप्त होता है, लेकिन आप "डॉट्समेटिंग" विधि को ओवरराइड नहीं करते हैं।

जब संकलक इस कोड को सीधा करता है …

C c = new C(); c.doSomething(); 

… विधि का कार्यान्वयन क्या करना चाहिए? बिना किसी स्पष्टीकरण के, संकलक को अस्पष्टता से हल करने के लिए यह असंभव है।

ओवरराइडिंग के अलावा, एकाधिक भाग के साथ दूसरी बड़ी समस्या मेमोरी में भौतिक वस्तुओं का लेआउट है।

सी ++ और जावा और सी # जैसी भाषाएं प्रत्येक प्रकार के ऑब्जेक्ट के लिए एक निश्चित पता-आधारित लेआउट तैयार करती हैं। कुछ इस तरह:

 class A: at offset 0 ... "abc" ... 4 byte int field at offset 4 ... "xyz" ... 8 byte double field at offset 12 ... "speak" ... 4 byte function pointer class B: at offset 0 ... "foo" ... 2 byte short field at offset 2 ... 2 bytes of alignment padding at offset 4 ... "bar" ... 4 byte array pointer at offset 8 ... "baz" ... 4 byte function pointer 

जब कंपाइलर मशीन कोड (या बाइटकोड) उत्पन्न करता है, तो यह प्रत्येक विधि या फ़ील्ड तक पहुंचने के लिए उन संख्यात्मक ऑफसेट का उपयोग करता है।

एकाधिक वंशानुगत यह बहुत मुश्किल बना देता है

यदि वर्ग सी दोनों को ए और बी से मिला है, तो संकलक को तय करना होगा कि एबी क्रम में या बीए क्रम में डेटा ले जाना है या नहीं।

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

इस तरह की प्रणाली को संभालने का तरीका तय-लेआउट दृष्टिकोण को खाएं, जिससे प्रत्येक ऑब्जेक्ट फ़ंक्शन या उसके खेतों तक पहुंचने के प्रयास से पहले उसके लेआउट के लिए पूछताछ की जा सके।

तो … लंबी कहानी छोटी … संकलक लेखकों के लिए कई विरासत का समर्थन करने के लिए गर्दन में दर्द है। तो जब गिदो वैन रॉसम की तरह कोई अजगर तैयार करता है, या जब ऐन्डर्स हेजल्बर्ग डिजाइन को सी # करता है, तो वे जानते हैं कि एकाधिक वंशानुगतों का समर्थन करने से कंपाइलर कार्यान्वयन काफी अधिक जटिल हो रहा है, और संभवतः उन्हें नहीं लगता कि इसका लाभ लागत के लायक है

आप जिन समस्याओं का उल्लेख करते हैं, वे वास्तव में हल नहीं करना कठिन हैं। वास्तव में ईफेल ऐसा बिल्कुल अच्छी तरह से करता है! (और मनमाने विकल्पों की शुरुआत के बिना या जो भी)

उदाहरण यदि आप ए और बी से हो, तो दोनों विधि foo () हो, तो निश्चित रूप से आप अपने वर्ग सी में एक मनमाना पसंद नहीं चाहते हैं, जो कि ए और बी दोनों से विरासत में लेना चाहते हैं। आपको फू को फिर से परिभाषित करना होगा, इसलिए यह स्पष्ट होगा कि क्या होगा अगर c.foo () को कहा जाता है या अन्यथा आपको सी में तरीकों में से एक का नाम बदलना है (यह बार () हो सकता है)

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

हीरा समस्या :

एक अस्पष्टता जो तब उत्पन्न होती है जब दो वर्ग बी और सी बी से उत्तराधिकारी होते हैं, और वर्ग डी दोनों बी और सी से प्राप्त होता है। अगर ए में एक विधि है कि बी और सी ओवरराइड किया गया है , और डी इसे ओवरराइड नहीं करता, तो उस संस्करण का संस्करण डी का उत्तोलन होता है: बी का, या सी का?

… इस स्थिति में वर्ग विरासत आरेख के आकार के कारण इसे "हीरा समस्या" कहा जाता है। इस मामले में, कक्षा ए शीर्ष पर है, दोनों नीचे बी और सी अलग से, और डी दोनों एक साथ मिलकर एक हीरे की आकृति बनाने के लिए …

मल्टीपल इनहेरिटमेंट उन चीजों में से एक है जिसे अक्सर प्रयोग नहीं किया जाता है, और इसका दुरुपयोग किया जा सकता है, लेकिन कभी-कभी जरूरत पड़ती है

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

मान लें कि आपके पास ऑब्जेक्ट ए और बी है, जो दोनों सी। ए और बी दोनों के द्वारा विरासत में मिली हैं, foo () और सी दोनों को कार्यान्वित करते हैं। मैं सीफ़ू () कहता हूं। कौन सा कार्यान्वयन चुना जाता है? इसमें अन्य समस्याएं हैं, लेकिन इस प्रकार की बात एक बड़ा है

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

जब आप एक ही आधार वर्ग से उत्तीर्ण कई वर्गों से प्राप्त करते हैं, तो यह बदतर हो जाता है। (हीरा विरासत, यदि आप विरासत के पेड़ को आकर्षित करते हैं तो आप हीरे की आकृति प्राप्त करते हैं)

इन समस्याओं को दूर करने के लिए एक संकलक के लिए वास्तव में समस्याग्रस्त नहीं हैं लेकिन पसंद करने के लिए कंपाइलर को यहां पर मनमाना करना पड़ता है, यह कोड को बहुत कम सहज बनाता है

मुझे लगता है कि जब ओ ओ डिजाइन अच्छा कर रहा है तो मुझे कभी भी कई विरासत की आवश्यकता नहीं है मामलों में मुझे इसकी ज़रूरत पड़ती है मैं आम तौर पर पता लगाता हूं कि मैं कार्यक्षमता का पुन: उपयोग करने के लिए विरासत का उपयोग कर रहा हूं, जबकि विरासत "केवल-एक" संबंधों के लिए ही उपयुक्त है

ऐसी अन्य तकनीकें हैं जो मिक्सिक्स जैसी समस्याएं सुलझती हैं और उन मुद्दों को नहीं मिलती हैं जिनके पास कई विरासत हैं।

मुझे नहीं लगता कि हीरा की समस्या एक समस्या है, मैं उस सोविज्ञान पर विचार करेगा, और कुछ नहीं।

सबसे बड़ी समस्या, मेरे दृष्टिकोण से, कई विरासत के साथ आरएडी – पीड़ित और लोग जो डेवलपर्स होने का दावा करते हैं लेकिन वास्तव में आधा ज्ञान (सर्वोत्तम) के साथ फंस गए हैं।

व्यक्तिगत रूप से, मैं बहुत खुश होगा यदि मैं अंत में विंडोज फॉर्म में कुछ ऐसा कर सकता हूं (यह सही कोड नहीं है, लेकिन आपको यह विचार देना चाहिए):

 public sealed class CustomerEditView : Form, MVCView<Customer> 

यह कोई मुख्य मुद्दा नहीं है जिसके पास कोई बहु विरासत नहीं है I आप इंटरफेस के साथ कुछ ऐसा कर सकते हैं, लेकिन मैं क्या "कोड ***" कहता हूं, यह दर्दनाक दोहराव सी है *** उदाहरण के लिए, डेटा संदर्भ प्राप्त करने के लिए आपको अपनी प्रत्येक कक्षा में लिखना होगा।

मेरी राय में, आधुनिक भाषा में कोड के किसी भी पुनरावृत्ति के लिए, थोड़ी सी भी नहीं, कोई आवश्यकता नहीं होनी चाहिए।

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

कई विरासत में स्वयं कुछ भी गलत नहीं है समस्या उस भाषा के लिए एकाधिक विरासत जोड़ने के लिए है, जिसे प्रारंभ से ही कई विरासत के साथ डिज़ाइन नहीं किया गया था।

एफिल भाषा एक बहुत ही कुशल और उत्पादक तरीके से प्रतिबंध के बिना कई विरासत का समर्थन कर रही है लेकिन उस भाषा से इसे समर्थन देने के लिए भाषा तैयार की गई थी।

यह सुविधा कंपाइलर डेवलपर्स के लिए लागू करने के लिए जटिल है, लेकिन ऐसा लगता है कि यह दोष इस तथ्य से मुआवजा सकता है कि एक अच्छा बहु उत्तराधिकार समर्थन अन्य सुविधाओं (यानी इंटरफ़ेस या एक्सटेंशन विधि की आवश्यकता नहीं) के समर्थन से बच सकता है।

मुझे लगता है कि एकाधिक वंशानुगतों का समर्थन करना या न ही अधिक पसंद का मामला है, प्राथमिकताओं का मामला एक और अधिक जटिल सुविधा को सही ढंग से कार्यान्वित और संचालन के लिए अधिक समय लगता है और अधिक विवादास्पद हो सकता है। C ++ कार्यान्वयन का कारण हो सकता है कि C # और Java में एकाधिक वंशानुक्रम लागू नहीं किया गया था …

जावा और। नेट जैसी चौखटे के डिजाइन लक्ष्यों में से एक यह है कि यह कोड के लिए संभव है जिसे पूर्व-संकलित लाइब्रेरी के एक संस्करण के साथ काम करने के लिए संकलित किया गया है, ताकि उस पुस्तकालय के बाद के संस्करणों के साथ समान रूप से अच्छी तरह से काम किया जा सके, भले ही उन बाद के संस्करण नई विशेषताएं जोड़ें जबकि सी या सी ++ जैसे भाषाओं में सामान्य प्रतिमान को स्थैतिक रूप से जुड़े निष्पादनयोग्य वितरित करना है, जिसमें उन सभी पुस्तकालयों की आवश्यकता होती है, जो एनएटी और जावा में प्रतिमान है, उन घटकों के संग्रह के रूप में वितरित करना है जो रन-टाइम में "लिंक" हैं ।

कॉम मॉडल, जो पहले से ही सामान्य दृष्टिकोण का उपयोग करने का प्रयास करता था, लेकिन इसके पास वास्तव में विरासत नहीं था – इसके बजाए, प्रत्येक वर्ग की परिभाषा प्रभावी ढंग से एक वर्ग और एक ही नाम के एक इंटरफ़ेस को परिभाषित करती है जिसमें उसके सभी सार्वजनिक सदस्यों को शामिल किया गया था। उदाहरण वर्ग के प्रकार थे, जबकि संदर्भ इंटरफ़ेस प्रकार के थे। दूसरे वर्ग से प्राप्त होने वाले एक वर्ग की घोषणा दूसरे वर्ग के इंटरफेस को लागू करने के लिए एक वर्ग को घोषित करने के समान थी, और उन सभी वर्गों के सभी सार्वजनिक सदस्यों को पुन: लागू करने के लिए आवश्यक होना चाहिए जिसमें से एक व्युत्पन्न हुआ था। यदि वाई और जेड एक्स से प्राप्त होते हैं, और फिर वाई और जेड से प्राप्त होता है, तो इससे कोई फर्क नहीं पड़ेगा कि वाई और जे एक्स के सदस्यों को अलग तरह से लागू करते हैं, क्योंकि Z उनके कार्यान्वयन का उपयोग करने में सक्षम नहीं होगा – इसे अपने खुद। डब्ल्यू वाई और / या जेड के उदाहरणों को समाहित कर सकता है, और एक्स के तरीकों के उनके क्रियान्वयन को उनके द्वारा श्रृंखलाबद्ध कर सकता है, लेकिन एक्स के तरीकों को क्या करना चाहिए, इस बारे में कोई अस्पष्टता नहीं होगी – वे जेड के कोड को स्पष्ट रूप से निर्देशित करने के लिए निर्देशन करते थे।

जावा और .NET में कठिनाई यह है कि कोड को सदस्यों के वारिस होने की अनुमति दी गई है और उन तक पहुंच के लिए मूल रूप से माता-पिता के सदस्यों को देखें। मान लीजिए कि किसी के पास उपर्युक्त के रूप में डब्लूज़ेड वर्ग हैं:

 class X { public virtual void Foo() { Console.WriteLine("XFoo"); } class Y : X {}; class Z : X {}; class W : Y, Z // Not actually permitted in C# { public static void Test() { var it = new W(); it.Foo(); } } 

यह W.Test() तरह प्रतीत होता है कि डब्ल्यू का एक उदाहरण बनाना चाहिए जो X में परिभाषित आभासी विधि Foo के कार्यान्वयन को कहते हैं। मान लीजिए, हालांकि, कि वाई और जेड वास्तव में एक पृथक-संकलित मॉड्यूल में थे, और यद्यपि उनको ऊपर से परिभाषित किया गया था जब एक्स और डब्ल्यू संकलित हुए, बाद में उन्हें बदल दिया गया और पुनः कंपाइल किया गया:

 class Y : X { public override void Foo() { Console.WriteLine("YFoo"); } class Z : X { public override void Foo() { Console.WriteLine("ZFoo"); } 

अब W.Test() फोन करने का क्या असर होना चाहिए? अगर कार्यक्रम को वितरण से पहले स्थैतिक रूप से जोड़ा जाना था, तो स्थिर लिंक चरण यह जान सकता है कि जब वाई और जेड बदल दिए जाने से पहले कार्यक्रम में कोई अस्पष्टता नहीं थी, तो वाई और जेड में परिवर्तन ने चीजों को अस्पष्ट बना दिया है और लिंकर इनकार कर सकता है इस कार्यक्रम का निर्माण जब तक कि इस तरह की अस्पष्टता हल नहीं किया जाता है। दूसरी ओर, यह संभव है कि जिस व्यक्ति को डब्ल्यू और वाई और जेड दोनों के नए संस्करण हैं, वह ऐसा कोई है जो केवल कार्यक्रम को चलाने के लिए चाहता है और इसका किसी भी स्रोत के लिए कोई स्रोत कोड नहीं है। जब W.Test() चलाता है, तो यह अब स्पष्ट नहीं होगा कि W.Test() को क्या करना चाहिए, लेकिन जब तक उपयोगकर्ता वाई और जेड के नए संस्करण के साथ डब्ल्यू चलाने की कोशिश नहीं करता तब तक सिस्टम का कोई भी हिस्सा नहीं हो सकता था पहचानें कि एक समस्या थी (जब तक वाई को वाई और जेड के परिवर्तन से पहले नाजायज़ माना जाता था)।

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

दूसरी ओर, आभासी विरासत के साथ यह बहुत आसानी से नियंत्रण से बाहर हो जाता है (और फिर एक गड़बड़ हो जाती है) उदाहरण के लिए एक "दिल" चित्र के रूप में देखें:

  AA / \ / \ BCDE \ / \ / FG \ / H 

सी ++ में यह पूरी तरह से असंभव है: जैसे ही F और G एकल कक्षा में विलीन हो जाते हैं, उनके A को भी विलय कर दिया जाता है, अवधि। इसका अर्थ है कि आप सी ++ में आधार कक्षाओं को अपारदर्शी नहीं मान सकते हैं (इस उदाहरण में आपको A में H का निर्माण करना होगा ताकि आपको यह पता होना पड़े कि यह पदानुक्रम में कहीं मौजूद है)। अन्य भाषाओं में यह काम कर सकता है, हालांकि; उदाहरण के लिए, F और G स्पष्ट रूप से ए को "आंतरिक" के रूप में स्पष्ट रूप से घोषित कर सकते हैं, जिसके परिणामस्वरूप परिणामस्वरूप विलय और प्रभावी रूप से खुद को ठोस रूप से बनाते हैं।

एक और दिलचस्प उदाहरण ( नहीं C ++ – विशिष्ट):

  A / \ BB | | CD \ / E 

यहां, केवल B वर्चुअल विरासत का उपयोग करता है तो E में दो B जो कि समान A साझा करता है इस तरह, आप एक A* पॉइंटर प्राप्त कर सकते हैं जो E को इंगित करता है, लेकिन आप इसे B* पॉइंटर पर नहीं डाल सकते हैं, हालांकि ऑब्जेक्ट वास्तव में B क्योंकि ऐसे कास्ट अस्पष्ट है, और यह अस्पष्टता समय संकलन में नहीं पाया जा सकता है (जब तक कम्पाइलर पूरे कार्यक्रम को नहीं देखता) यहां परीक्षण कोड है:

 struct A { virtual ~A() {} /* so that the class is polymorphic */ }; struct B: virtual A {}; struct C: B {}; struct D: B {}; struct E: C, D {}; int main() { E data; E *e = &data; A *a = dynamic_cast<A *>(e); // works, A is unambiguous // B *b = dynamic_cast<B *>(e); // doesn't compile B *b = dynamic_cast<B *>(a); // NULL: B is ambiguous std::cout << "E: " << e << std::endl; std::cout << "A: " << a << std::endl; std::cout << "B: " << b << std::endl; // the next casts work std::cout << "A::C::B: " << dynamic_cast<B *>(dynamic_cast<C *>(e)) << std::endl; std::cout << "A::D::B: " << dynamic_cast<B *>(dynamic_cast<D *>(e)) << std::endl; std::cout << "A=>C=>B: " << dynamic_cast<B *>(dynamic_cast<C *>(a)) << std::endl; std::cout << "A=>D=>B: " << dynamic_cast<B *>(dynamic_cast<D *>(a)) << std::endl; return 0; } 

इसके अलावा, कार्यान्वयन बहुत जटिल हो सकता है (भाषा पर निर्भर करता है, बेंज़िस्मथ का उत्तर देखें)