2009-03-16 20 views
11

कुछ समय के लिए, मैं अपने सिर को लपेटने की कोशिश कर रहा हूं क्योंकि कुछ "नरभक्षक" वर्गों को संकलित करने की अनुमति क्यों है।कैनिबिल क्लासेस

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

मैं मूल रूप से एक कैनिबिल कक्षा को एक कक्षा कहता हूं जो स्वयं को खपत करता है। दूसरे शब्दों में एक वर्ग जिसका इंटरफ़ेस अपने स्वयं के प्रकार के सदस्यों की घोषणा करता है। उदाहरण के लिए:

class Foo 
{ 
    public Foo SomeFoo; 
} 

जैसा कि आप ऊपर देख सकते हैं, कक्षा फू के प्रकार फू (स्वयं) के सदस्य हैं।

अब, पहली बार मैंने यह देखा (लूंग समय पहले) मैंने यह नहीं किया कि यह संकलित करने जा रहा था, लेकिन यह आश्चर्य की बात है कि यह संकलित करता है। जिस कारण से मैंने यह नहीं किया, यह संकलित होगा क्योंकि मेरे लिए यह कुछ प्रकार के पुनरावर्ती दुःस्वप्न चिल्लाता है।

बातें थोड़ा और आगे को मुश्किल करने के लिए, मैं एक ही बात की कोशिश करने का फैसला किया है लेकिन इस तरह के रूप में कक्षा एक struct बनाने:

struct Foo 
{ 
    public Foo SomeFoo; 
} 

दुर्भाग्य से, यह संकलन नहीं करता है, बजाय प्राप्त होने वाले त्रुटि: Struct सदस्य प्रकार 'फू' के 'Foo.SomeFoo' struct लेआउट में एक चक्र

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

धन्यवाद।

+1

एलओएल कैनिबेल कक्षा। इससे मुझे हंसी मिली :) –

+0

कभी नहीं सुना है कि इसे आमतौर पर एक कैनिबेल कहा जाता है जिसे स्वयं संदर्भित किया जाता है लेकिन मुझे कैनिबेल बहुत बेहतर लगता है। – JoshBerke

उत्तर

24

कारण आप इस तरह एक struct डिजाइन नहीं कर सकते क्योंकि structs जब वे कुछ मूलभूत मूल्यों के साथ आवंटित किए जाते हैं प्रारंभ किया जाना है है। तो, आप एक struct Foo है जब की तरह आप का वर्णन किया और आप एक Foo ...

Foo x; // x = default(Foo) 

यह Foo के लिए डिफ़ॉल्ट निर्माता कॉल पैदा करते हैं। हालांकि, उस डिफ़ॉल्ट कन्स्ट्रक्टर को Foo.SomeFoo फ़ील्ड के लिए डिफ़ॉल्ट मान देना होगा।

अच्छा, यह कैसा लगता है? इसे default(Foo) पर कॉल करना है। जो, Foo बनाने के लिए, Foo.SomeFoo फ़ील्ड के लिए डिफ़ॉल्ट मान देना होगा ... जैसा कि आपने अनुमान लगाया है, यह एक पुनरावर्ती दुःस्वप्न है।

चूंकि आप कक्षा के लिए एक संक्षिप्त संदर्भ बना सकते हैं, और वास्तव में कक्षा के उदाहरण को तुरंत बनाने से बच सकते हैं, कोई समस्या नहीं है; आप new Foo() और Foo.SomeFoo पर कॉल कर सकते हैं बस शून्य हो जाएगा। कोई रिकर्सन आवश्यक नहीं है।

परिशिष्ट: जब आप इस बारे में सोच रहे हैं, अगर आप अभी भी असमंजस में हैं, मुझे लगता है कि अन्य उत्तर यह विचार (एक ही आवश्यक समस्या, अलग दृष्टिकोण) का एक और अच्छा तरीका है - जब कार्यक्रम स्मृति आवंटित Foo के लिए, इसे कैसे करना चाहिए?sizeof(Foo) क्या है जब Foo में कुछ सामान शामिल है, और फिर एक और पूरा Foo है? आप ऐसा नहीं कर सकते

इसके बजाय, यदि यह एक वर्ग था, तो उसे Foo के संदर्भ के लिए केवल दो बाइट आवंटित करना होगा, वास्तविक Foo नहीं, और कोई समस्या नहीं है।

+0

संक्षेप में: वर्ग = संदर्भ प्रकार, संरचना = मान प्रकार। आप स्वयं के एक प्रकार के मेमोरी मैप को लेआउट नहीं कर सकते हैं। हालांकि, संदर्भ प्रकारों में केवल स्मृति संदर्भ होगा, वास्तविक डेटा संरचना नहीं। इसलिए, यह जानना आवश्यक नहीं है कि संकलन समय पर उस प्रकार को कैसे संरचित किया जाता है। – spoulson

0

तो क्या आप सिंगलटन कार्यान्वयन को कैनबिल क्लास कहते हैं?

public class ShopSettings 
{ 
    public static ShopSettings Instance 
    { 
    get 
    { 
     if (_Instance == null) 
     { 
     _Instance = new ShopSettings(); 
     } 

     return _Instance; 
    } 
    } 
} 
+0

-1, नहीं, स्थिरता में आपका उदाहरण और पूरी तरह से इस समस्या से बच जाएगा। – Samuel

1
class Foo 
{ 
    public Foo SomeFoo; 
} 

इस उदाहरण में SomeFoo सिर्फ एक लिंक - और पुनरावर्ती समस्या बनाने नहीं है।
और इसके कारण, कैनबिल कक्षाएं मौजूद हो सकती हैं।

12

अंतर इस तथ्य में निहित है कि फू एक संदर्भ प्रकार है। क्लास मेमोरी लेआउट में एक फू इंस्टेंस के लिए पॉइंटर होगा और यह ठीक होगा।

संरचना के मामले में, आपके पास मूल रूप से एक बेहद पुनरावर्ती स्मृति लेआउट है, जो काम नहीं कर सकता है।

अब, यदि आपकी कक्षा अपने स्वयं के कन्स्ट्रक्टर में फू को तुरंत चालू करने का प्रयास करती है, तो आपके पास एक स्टैक ओवरफ़्लो समस्या होगी।

+0

यह सही उत्तर है। मूल्य प्रकार और संदर्भ प्रकारों के बीच अंतर, जो structs और वर्गों के बीच अंतर है। डिफ़ॉल्ट मान समस्या इसका एक परिणाम है। –

0

जैसा कि उन्होंने कहा कि यह एक वैल्यूटाइप है, इसलिए इसमें स्वयं शामिल नहीं हो सकता है, क्योंकि यह केवल काम नहीं कर सकता है (इसके बारे में सोचें)।

आप फिर भी निम्न कर सकते हैं:

unsafe struct Foo 
{ 
    public Foo* SomeFoo; 
} 
5

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

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

+0

मैंने अभी एक ऐसी चीज़ का आविष्कार किया जिसमें स्वयं की एक प्रति शामिल है ... मुझे लगता है कि मैं इसे एक फ्रैक्टल कहूंगा! :) –

+0

आह, लेकिन फ्रैक्टल _don't_ में स्वयं की एक पूर्ण प्रति शामिल है। इसके बजाय, कुछ फ्रैक्टल के कुछ हिस्सों को कुछ मैपिंग के तहत, कुछ ईपीएसलॉन तक पत्राचार में रखा जा सकता है। – MarkusQ

1

ठीक है, मैं देखता हूं।

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

तो अगर यह एक 32 बिट ओएस के लिए संकलित किया जा रहा था, तो मुझे लगता है कि संकलक तकनीकी रूप से की तरह कुछ करने के लिए फू प्रकार की घोषणा बदल रहा है:

class Foo 
{ 
    public Int32 SomeFoo; 
} 
बजाय

"फू" संकलक है वास्तव में 32 बिट्स (प्रकार) देख रहे हैं।

धन्यवाद।

+0

आखिरकार, स्मृति-वार, हां। –

1

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

http://cyberkruz.vox.com/library/post/c-tutorial-linked-list.html

तुम देखो की जाँच, वे एक नोड वर्ग को परिभाषित इस प्रकार है:

public class LinkedList 
{ 

    Node firstNode; 

    public class Node 
    { 

     Node previous; 
     Node next; 
     int value; 
    } 
} 

कहाँ पिछले और अगले नोड के लिए प्रत्येक नोड अंक है, तो किसी अन्य वस्तु के लिए एक लिंक के रूप में यह के बारे में सोच एक अच्छी शुरुआत है।

यदि आपने पहले लिंक्ड लिस्ट नहीं किया है, तो मैं अत्यधिक अनुशंसा करता हूं क्योंकि यह एक अच्छा एक्सर्ससाइज है।

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