2012-04-24 19 views
11

2 कक्षाएं, एक है और बी बी एCython और सी ++ विरासत

//C++  
class A 
{ 
    public: 
     int getA() {return this->a;}; 
     A() {this->a = 42;} 
    private: 
     int a; 

}; 

class B: public A 
{ 
    public: 
     B() {this->b = 111;}; 
     int getB() {return this->b;}; 
    private: 
     int b; 

}; 

अब मैं Cython उपयोग करने वालों के दो वर्गों इंटरफेस और संभावना Geta कॉल करने के लिए करना चाहते हैं() विधि से विरासत

a = PyA() 
b = PyB() 
assert a.getA() == b.getA() 

वर्तमान में मेरी सिक्कों के नमूने रखने का बक्स फ़ाइल इस तरह दिखता है:

cdef extern from "Inherit.h" : 
    cdef cppclass A: 
     int getA() 

    cdef cppclass B(A): 
     int getB() 


cdef class PyA: 
    cdef A* thisptr 

    def __cinit__(self): 
     print "in A: allocating thisptr" 
     self.thisptr = new A() 
    def __dealloc__(self): 
     if self.thisptr: 
      print "in A: deallocating thisptr" 
      del self.thisptr 

    def getA(self): 
     return self.thisptr.getA() 

cdef class PyB(PyA): 
    def __cinit__(self): 
     if self.thisptr: 
      print "in B: deallocating old A" 
      del self.thisptr 
     print "in B: creating new b" 
     self.thisptr = new B() 

    def __dealloc__(self): 
     if self.thisptr: 
      print "in B: deallocating thisptr" 
      del self.thisptr 
      self.thisptr = <A*>0 

    def getB(self): 
     return (<B*>self.thisptr).getB() 

मुझे आशा है कि एक ओर जहां यह कोड n है एक बी उदाहरण से कुछ भी खतरनाक कर रहा हूं, मुझे उम्मीद है कि इसे संभालने का एक बेहतर तरीका है।

इसके अलावा मॉड्यूल का उपयोग कर निम्न उत्पादन उत्पन्न करता है:

>>> from inherit import * 
>>> b = PyB() 
in A: allocating thisptr 
in B: deallocating old A 
in B: creating new b 
>>> b.getA() 
42 
>>> b.getB() 
111 
>>> del b 
in B: deallocating thisptr 

और मैं वास्तव में सिर्फ यह तुरंत बाद मुक्त करने के लिए एक एक उदाहरण हिस्सा आवंटित करना नहीं है।

इसे सही तरीके से कैसे करें इसके बारे में कोई सलाह?

उत्तर

7

मैं कुछ प्रयोग करते हैं, और पूरी तरह से तैयार उत्तर है, लेकिन अब मैं देख जहां समस्या है:

अपने एक्सटेंशन प्रकार एक आधार प्रकार, आधार प्रकार के __cinit__ विधि स्वतः से पहले कहा जाता है है

हैं आपकी __cinit__ विधि कहलाती है; आप विरासत में मिली __cinit__ विधि को स्पष्ट रूप से कॉल नहीं कर सकते हैं।

तो वास्तविक समस्या यह है कि साइथन प्रकारों में अभी भी कन्स्ट्रक्टर नहीं हैं, केवल पूर्व प्रारंभकर्ता हुक __cinit__ जो डिफ़ॉल्ट कन्स्ट्रक्टर की तरह व्यवहार करते हैं। आप कन्स्ट्रक्टर से वर्चुअल विधि को कॉल नहीं कर सकते हैं और आप इसे __cinit__ से कॉल नहीं कर सकते हैं (यदि आप कॉल करते हैं, तो यह गैर वर्चुअल जैसा व्यवहार करता है)।

किसी भी तरह __cinit__type(self) सही प्रकार की वस्तु वापस लौटाता है, लेकिन यह बेकार है। साइथन में स्थैतिक फ़ील्ड नहीं हैं, विधियों और प्रकार वस्तु केवल type (कोई मेटाक्लास नहीं) का उदाहरण हो सकती है। पायथन @staticmethod आसान अतिसंवेदनशील है, इसलिए यह बेकार है।

तो def __init__(self): के अंदर आवंटन डालने की कोई अन्य तरीका नहीं है, और जहां भी आप इसका उपयोग करते हैं, प्रारंभिक thisptr की जांच करें।

आप वैश्विक डमी सी ++ ऑब्जेक्ट बनाने पर विचार कर सकते हैं, और जांच और क्रैश होने से बचने के लिए इसे thisptr पर असाइन कर सकते हैं। कोई पोस्ट प्रारंभकर्ता हुक नहीं है, इसलिए आप यह जांचने में असमर्थ होंगे कि सही प्रारंभिकरण पहले से ही हुआ है या नहीं।

3

मैंने कभी साइथन पर आँखें नहीं रखी हैं, इसलिए अगर यह रास्ता बंद है तो कृपया मुझे क्षमा करें। यही कारण है कि ने कहा:

C++ में, किसी भी समय आप bar : foo (barfoo से इनहेरिट), अगर foo एक डिफ़ॉल्ट निर्माता है, यह स्वचालित रूप से जब bar बनाई गई है बुलाया जाएगा है .... जब तक आप के लिए अपने स्वयं के कस्टम निर्माता फोन माता पिता।

मुझे पायथन नहीं पता है, लेकिन कुछ त्वरित गूगलिंग मुझे बताता है कि वही सिद्धांत लागू होते हैं। यानी PyA के लिए डिफ़ॉल्ट कन्स्ट्रक्टर केवल तभी बुलाया जाएगा जब PyB मैन्युअल रूप से किसी अन्य को कॉल नहीं करता है।

उस स्थिति में, इस काम को कुछ पसंद नहीं होगा?

cdef class PyA: 
    cdef A* thisptr 

    def __cinit__(self, bypasskey="") 
     if bypasskey == "somesecret" 
      print "in A: bypassing allocation" 
     else 
      print "in A: allocating thisptr" 
      self.thisptr = new A() 

... 

cdef class PyB(PyA): 
    def __cinit__(self): 
     super(PyB, self).__init__("somesecret") 

आपको याद है, मुझे यकीन है कि यह कच्चा है। लेकिन शायद यहां विचार आपको काम करने के लिए कुछ देगा?


यहां एक और विचार है। मैं लगभग यह काम करेंगे कुछ कर रहा हूँ (लेकिन वाक्य रचना बंद है कि), और यह निश्चित रूप से ऊपर की तुलना में बहुत क्लीनर है:

cdef class PyA: 
    cdef A* thisptr 

    def __cinit__(self, t=type(A)) 
      self.thisptr = new t() 

... 

cdef class PyB(PyA): 
    def __cinit__(self): 
     super(PyB, self).__init__(type(B)) 

या हो सकता है यह इस तरह दिखना करेंगे?

cdef class PyA: 
    cdef A* thisptr 

    def __cinit__(self, t=A) 
      self.thisptr = new t() 

... 

cdef class PyB(PyA): 
    def __cinit__(self): 
     super(PyB, self).__init__(B) 

मैं इनाम के लिए इस पोस्टिंग नहीं कर रहा हूँ (और आप किसी को भी निर्दिष्ट करने के लिए मजबूर नहीं कर रहे हैं), मैं सिर्फ तुम्हारे साथ कुछ विचारों को साझा कर रहा हूँ।

मुझे लगता है कि आप/"दुभाषिया दुर्घटनाग्रस्त" से बचने के लिए सक्षम होना चाहिए कर सकते हैं अगर आप या तो

क) दूसरे निर्माता केवल ख के लिए दिखाई दे (यदि यह संभव है पता नहीं है), या

बनाने

बी) जांचें कि यह कहीं और उपयोग करने से पहले शून्य है, या

सी) जांचें कि कॉलिंग फ़ंक्शन आवंटन को छोड़ने से पहले बी के लिए निर्माता था।

इसके अलावा, साइथन सी ++ प्रलेखन makes it rather clear कि सभी सी ++ अनुकूलन के लिए बेवकूफ समाधान नहीं हो सकते हैं, अस्पष्ट, हाथ से भरे उद्धरण जैसे "यह दूसरों द्वारा कुछ प्रयोग कर सकता है (आप?) के सबसे शानदार तरीके खोजने के लिए इस मुद्दे को संभालना। "

+0

अच्छी तरह से, एक इनाम खोलने के द्वारा, मैं एक मुहावरेदार निर्माण के लिए देख रहा था इस मामले के लिए। आप कहते हैं कि आप अजगर और Cython पता नहीं है। यदि आपका जवाब कानूनी अजगर (और Cython) कोड होने के लिए अनुकूलित किया जा सकता है, इस अजगर उपयोगकर्ता दुभाषिया है, जो मेरी राय है दुर्घटना शक्ति देना होगा स्मृति आवंटन बर्बाद कर से भी बदतर। – ascobol

+0

आप मेरे जबाब एक टिप्पणी के लिए बहुत लंबा है, कृपया मेरी पोस्ट के उत्तरार्ध में देखते हैं। –

+0

क) मुझे लगता है कि वहाँ केवल Cython में एक निर्माता, हो सकता है अजगर के रूप में। ख) तो हर विधि में हम एक सही आरंभीकरण ... ग) शायद इस सी मॉड्यूल में एक मनमाना पूर्व निर्धारित मूल्य के साथ संभव है के लिए जाँच करने की आवश्यकता होगी। पीईए __ cinit__ में हम इस गैर-तुच्छ मूल्य के साथ एक अतिरिक्त तर्क की जांच करेंगे जो आवंटन को बाईपास करेगा। इस मामले में कोई उपयोगकर्ता "दुर्घटना से" दुभाषिया को दुर्घटनाग्रस्त नहीं कर सकता है। – ascobol

1

(मैं दोनों अजगर और Cython के लिए नया हूँ, इसलिए क्या यह लायक है के लिए इस उत्तर से लेते हैं।) आप __cinit__ कार्यों के बजाय __init__ कार्यों में thisptr प्रारंभ करते हैं, तो चीजें अतिरिक्त आवंटन के बिना इस विशिष्ट उदाहरण में काम करने लगते हैं/हटाना जारी है ... मूल रूप से के लिए ऊपर अपना __cinit__ कार्यों बदलने के लिए:

def __init__(self): 
    print "in A: creating new A" 
    self.thisptr = new A() 

और

def __init__(self): 
    print "in B: creating new B" 
    self.thisptr = new B() 

क्रमशः। हालांकि, मुझे यकीन है कि यह कम से कम सैद्धांतिक रूप से असुरक्षित (और शायद व्यावहारिक रूप में अच्छी तरह से असुरक्षित है), लेकिन शायद किसी को इस पर टिप्पणी कर सकता है वास्तव में कैसे असुरक्षित ...

उदाहरण के लिए, Cython परिचय paper से हम जानते हैं कि "__init__ है कर रहा हूँ चलाने की गारंटी नहीं है (उदाहरण के लिए, कोई उप-वर्ग बना सकता है और पूर्वजों के निर्माता को कॉल करना भूल जाता है)।"मैं एक परीक्षण मामले में जहां यह तब होता है निर्माण करने में सक्षम नहीं किया गया है, लेकिन यह शायद मेरी ओर से अजगर ज्ञान की एक सामान्य कमी की वजह से है ...

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