2009-03-06 18 views
13

सी #कंस्ट्रक्टर्स और विरासत

public class Foo 
{ 
    public Foo() { } 
    public Foo(int j) { } 
} 

public class Bar : Foo 
{ 

} 

में एक उदाहरण लेते हैं अब, सभी फू की जनता के सदस्यों निर्माता को छोड़कर बार में पहुँचा जा सकता है की सुविधा देता है। मैं

Bar bb = new Bar(1); 

की तरह कुछ नहीं कर सकते क्यों कंस्ट्रक्टर्स दाय नहीं हैं?

अद्यतन

मैं समझता हूँ कि हम श्रृंखला कंस्ट्रक्टर्स कर सकते हैं, लेकिन मैं जानना चाहता है कि इसके बाद के संस्करण निर्माण मान्य नहीं है चाहते हैं। मुझे यकीन है कि इसके लिए एक वैध कारण होना चाहिए।

+0

http://stackoverflow.com/questions/426484/why-are-constructors-not-inherited –

उत्तर

14

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

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

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

रमेश - यह नहीं है कि आप जो भी वर्णन करते हैं वह किसी भाषा में जोड़ना असंभव होगा। आम तौर पर ऐसा नहीं किया जाता है क्योंकि इस प्रकार का व्यवहार लोगों को भ्रमित कर सकता है और बहुत से अतिरिक्त डिबगिंग और कोड लेखन का कारण बन सकता है।

क्विंटिन रॉबिन्सन टिप्पणियों में इस प्रश्न के कुछ फायदेमंद प्रतिक्रिया प्रदान करता है जो निश्चित रूप से पढ़ने योग्य हैं।

+0

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

+0

क्योंकि आप * व्युत्पन्न कक्षा में * गैर-बेस सदस्यों को आरंभ करने की आवश्यकता हो सकती है। –

+0

@ सिमॉन - यदि ऐसा है, तो मैं हमेशा अपने रचनाकारों को फ़ंक्शन – Ramesh

7

वे (चेनिंग के माध्यम से) हैं, तो आप श्रृंखला के लिए अपनी व्युत्पन्न वस्तु में निर्माता होता .. आईई:

public class Foo 
{ 
    public Foo() { } 
    public Foo(int j) { } 
} 

public class Bar : Foo 
{ 
    public Bar() : base() { } 
    public Bar(int j) : base(j) { } 
} 

ली गई वस्तुओं में कंस्ट्रक्टर्स तो श्रृंखला होगी कॉल आधार में कंस्ट्रक्टर्स करना वस्तुओं।

This article यदि आप और पढ़ना चाहते हैं तो कुछ और उदाहरण प्रदान करते हैं।

+0

का डुप्लिकेट मैं चेनिंग को समझता हूं, लेकिन मेरा उदाहरण मान्य क्यों नहीं है जो मैं समझना चाहता हूं (मेरे पास है इसे हाइलाइट करने के लिए प्रश्न को अपडेट किया गया) – Ramesh

+0

मुझे लगता है कि एक प्रश्न का उत्तर देने के लिए खेद है जिसे मैंने नहीं पूछा था, मुझे लगता है कि मैं थोड़ा बहुत दूर पढ़ता हूं। –

+0

धन्यवाद क्विंटिन, आपके प्रश्नों ने मुझे सोचा। एक और प्रश्न के लिए अपने उत्तरों में से एक के लिए +1। – Ramesh

0

मुझे लगता है कि आप निम्न कर सकते हैं:

public class Bar : Foo 
{ 
    public Bar (int i) 
    : base (i) 
    { 
    } 
} 

मैं थोड़ा दूर हो सकता है - लेकिन यह सामान्य विचार है।

+0

मैं चेनिंग को समझता हूं, लेकिन मेरा उदाहरण मान्य नहीं है, जिसे मैं समझना चाहता हूं (मैंने इसे हाइलाइट करने के लिए प्रश्न अपडेट किया है) – Ramesh

1

रचनाकार डिजाइन कारणों से विरासत योग्य नहीं हैं। (ध्यान दें कि यह हर ऑब्जेक्ट उन्मुख भाषा में एक ही स्थिति है जिसे मैं जानता हूं।) सरल जवाब यह है कि कई मामलों में आप वास्तव में बेस क्लास के रूप में उपलब्ध नहीं होने वाले समान रचनाकारों को नहीं चाहते हैं। कुछ और पूर्ण स्पष्टीकरण के लिए this SO thread देखें।

0

सरल जवाब यह है कि भाषा इस तरह से काम नहीं करती है।

असली सवाल जो आप पूछ रहे हैं, यही कारण है कि यह इस तरह से काम नहीं करता है :-) वैसे यह एक मनमाना विकल्प है, और यह सी ++ और जावा (और संभवतः कई अन्य लैंगुग जो सी # को प्रभावित करता है) से चलता है। ।

संभावित कारण यह है कि संकलक केवल एक कन्स्ट्रक्टर उत्पन्न करेगा जो कोई तर्क नहीं लेता है और केवल माता-पिता को कॉल करता है कि यदि आप संकलक से अधिक चाहते हैं तो आप इसे स्वयं करते हैं। यह सबसे अच्छा विकल्प है क्योंकि आप पैरेंट कन्स्ट्रक्टर को कॉल करने के लिए बाधाओं से अधिक कुछ करते हैं।

2

एक कारण है कि आप कक्षा में एक निर्माता को पेश कर सकते हैं क्योंकि यह किसी विशिष्ट "निर्भरता" के बिना उस वर्ग का उदाहरण रखने का कोई मतलब नहीं है।

public class FooRepository 
{ 
    public FooRepository(IDbConnection connection) { ... } 
} 

अगर आधार वर्ग से सभी सार्वजनिक कंस्ट्रक्टर्स उपलब्ध थे, तो अपने भंडार वर्ग के एक उपयोगकर्ता के लिए सक्षम हो जाएगा: उदाहरण के लिए, यह डेटा-पहुँच वर्ग एक डेटाबेस से जुड़ा हुआ नहीं है हो सकता है अपने वर्ग के गलत उदाहरण बनाने के लिए System.Object के डिफ़ॉल्ट निर्माता का उपयोग करें:

var badRepository = new FooRepository(); 

डिफ़ॉल्ट रूप से विरासत में मिला कंस्ट्रक्टर्स छिपाई जा रही है मतलब है कि आप "अवैध" उदाहरणों बनाने उपयोगकर्ताओं के बारे में चिंता किए बिना निर्भरता लागू कर सकते हैं।

+0

+1 - मुझे समझ में आता है कि विधियों को छिपाने की आवश्यकता नहीं है, लेकिन कन्स्ट्रक्टर को इंटिलाइजेशन कारण के लिए होना चाहिए। – Ramesh

1

कुछ विचार विमर्श

मूल विचार संभव के रूप में निर्माता के रूप में ज्यादा नियंत्रण प्रदान करना है। और आपके पास निजी आधार हो सकते हैं। तब आप ऑब्जेक्ट कैसे बनाते थे? आधार "अरे:

2

Foo निर्माता केवल एक फू वस्तु को प्रारंभ करने के लिए कैसे पता कर सकते हैं, तो यह कोई मतलब नहीं है यह भी पता होना चाहिए कि किसी भी संभावित उपवर्ग

public class Bar : Foo 
{ 
public Bar(int i) : base(i) { } 
} 

कहानी निर्माता बताता प्रारंभ करने में कैसे है कक्षा कृपया एक अच्छी स्थिति में रहने के लिए आपको जो भी काम करने की ज़रूरत है, ताकि मैं आगे बढ़ सकूं और खुद को ठीक से स्थापित कर सकूं।

2

मान लीजिए कि रचनाकार विरासत में थे। आप कई मामलों में विरासत वाले कन्स्ट्रक्टर को कैसे अक्षम करेंगे, वे उप-वर्ग के लिए समझ में नहीं आते थे?

विरासत को अवरुद्ध करने के लिए एक तंत्र के साथ भाषा को जटिल बनाने की बजाय, भाषा डिजाइनरों ने केवल रचनाकारों को विरासत में नहीं बनाया है।

+0

+1 - सटीक उत्तरों में से एक – Ramesh

+0

यह बताए जाने के बारे में कि अगर किसी उप-वर्ग में कोई रचनाकार होता है, तो कोई अभिभावक कन्स्ट्रक्टर "विरासत में नहीं" होता है, लेकिन अन्यथा वे सभी होते हैं (जिसका अर्थ है कि रचनाकारों को मिलान के साथ मूल रचनाकारों को श्रृंखला के लिए स्वतः उत्पन्न किया जाएगा हस्ताक्षर)? कोई भी वर्ग जो अपने सभी माता-पिता के रचनाकारों को "उत्तराधिकारी" नहीं लेना चाहता, उसे कम से कम एक की आपूर्ति करनी चाहिए। यदि अभिभावक के पास पैरामीटर रहित कन्स्ट्रक्टर नहीं है, तो किसी भी निर्माता के साथ कक्षा के लिए कोई अन्य तार्किक अर्थ नहीं होगा। – supercat

0

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

संबंधित मुद्दे