2010-03-09 8 views
12

मेरे पास एक जटिल श्रेणी पदानुक्रम है जिसमें कक्षाएं एक-दूसरे के आधार पर क्रॉस-जैसी हैं: दो अमूर्त कक्षाएं ए और सी में एक विधि है जो क्रमशः सी और ए का उदाहरण देता है। विरासत में कक्षाओं में मैं एक सह-प्रकार का उपयोग करना चाहता हूं, जो इस मामले में एक समस्या है क्योंकि मुझे विरासत संबंध जहाज को आगे बढ़ाने का तरीका नहीं पता है।सी ++: मैं बिना किसी कास्टिंग के विरासत में कक्षाओं में "अवैध कॉन्वेंट रिटर्न प्रकार" से कैसे बच सकता हूं?

मुझे एक "test.cpp: 22: त्रुटि प्राप्त होती है: 'वर्चुअल डी * बी :: आउटसी()' के लिए अमान्य कॉन्वर्सट रिटर्न टाइप" - त्रुटि क्योंकि संकलक को पता नहीं है कि डी सी

का उप-वर्ग है
class C; 

class A { 
public: 
     virtual C* outC() = 0; 
}; 

class C { 
public: 
     virtual A* outA() = 0; 
}; 


class D; 

class B : public A { 
public: 
     D* outC(); 
}; 

class D : public C { 
public: 
     B* outA(); 
}; 

D* B::outC() { 
     return new D(); 
} 

B* D::outA() { 
     return new B(); 
} 

यदि मैं वापसी प्रकार बी :: आउटसी() से सी * को उदाहरण संकलित करता हूं। बी * और डी * को विरासत कक्षाओं में रिटर्न प्रकार के रूप में रखने का कोई तरीका है (यह मेरे लिए सहज होगा कि एक तरीका है)?

+2

क्या आपको वास्तव में उस प्रकार की उलझन की आवश्यकता है? (इसे युग्मन करना थोड़ा छोटा हो सकता है) –

+0

कभी-कभी यह भाषा की समस्या नहीं है, यह जिस तरह से हम इसका उपयोग करने की कोशिश करते हैं, उसमें एक समस्या है। यदि आपके दो पदानुक्रम इतने गहरे युग्मित हैं, तो मुझे लगता है कि आप एक पदानुक्रम के साथ बेहतर होंगे ('सी' और 'बी' के साथ 'बी' के साथ 'ए' को फ्यूज करना) क्योंकि ऐसा लगता है कि वे एक दूसरे के बिना काम नहीं कर सकते । –

+0

ठीक है, मेरे पास दो प्रकार के वर्ग हैं: एक कार्य और निष्पादक के लिए एक विनिर्देश जो वास्तव में कार्य निष्पादित करता है (कई धागे लॉन्च करता है)। विनिर्देश स्वयं कार्य के लिए एक कारखाना होना चाहिए और प्रत्येक निष्पादक को इसके विनिर्देश तक पहुंचने की आवश्यकता है। और उनके कार्यों के साथ विभिन्न विनिर्देश हैं। तो निष्पादक एक विनिर्देश लपेटता है, इसलिए युग्मन केवल एक दिशा में मजबूत होता है, दूसरी दिशा में यह केवल फैक्ट्री-विधि है। – Searles

उत्तर

7

पर एक नज़र डालें I C++ में सीधे युग्मित कॉन्वेंट सदस्यों को रखने का कोई तरीका नहीं है। आपके पास या तो एक परत जोड़ने के लिए होगा, या कॉन्वरेन्ट को अपने आप को वापस लागू करें।

पहला विकल्प

class C; 

class A { 
public: 
     virtual C* outC() = 0; 
}; 

class C { 
public: 
     virtual A* outA() = 0; 
}; 


class BI : public A { 
public: 
}; 

class D : public C { 
public: 
     BI* outA(); 
}; 

class B: public BI { 
public: 
     D* outC(); 
}; 

D* B::outC() { 
     return new D(); 
} 

BI* D::outA() { 
     return new B(); 
} 

के लिए और के लिए दूसरे

class C; 

class A { 
public: 
     C* outC() { return do_outC(); } 
     virtual C* do_outC() = 0; 
}; 

class C { 
public: 
     virtual A* outA() = 0; 
}; 


class D; 

class B : public A { 
public: 
     D* outC(); 
     virtual C* do_outC(); 
}; 

class D : public C { 
public: 
     B* outA(); 
}; 

D* B::outC() { 
     return static_cast<D*>(do_outC()); 
} 

C* B::do_outC() { 
     return new D(); 
} 

B* D::outA() { 
     return new B(); 
} 

नोट

कि इस दूसरा विकल्प क्या परोक्ष (कि static_cast मान्य है कुछ स्थिर चेकों के साथ) संकलक द्वारा किया जाता है है ।

0

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

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

+1

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

+1

मेरे उदाहरण में, कक्षा डी में सह-संस्करण वापसी प्रकार कोई समस्या नहीं है। – Searles

4

जहां तक ​​मुझे पता है, स्पष्ट कास्टिंग के बिना ऐसा करने का कोई तरीका नहीं है। समस्या वर्ग B की परिभाषा जानते हैं कि नहीं कर सकते कि DC का एक उपवर्ग है जब तक यह वर्ग D की एक पूरी परिभाषा देखता है, लेकिन वर्ग D की परिभाषा पता नहीं कर सकते हैं कि BA का एक उपवर्ग है जब तक यह देखता है कक्षा B की पूर्ण परिभाषा, और इसलिए आपके पास गोलाकार निर्भरता है। इसे आगे की घोषणाओं के साथ हल नहीं किया जा सकता है क्योंकि दुर्भाग्यवश एक अग्रिम घोषणा विरासत संबंध निर्दिष्ट नहीं कर सकती है।

टेम्पलेट्स, which I found can be solved का उपयोग कर एक कॉन्वेंट clone() विधि को कार्यान्वित करने की कोशिश करने में एक ही समस्या है, लेकिन समान समाधान अभी भी विफल रहता है क्योंकि परिपत्र संदर्भ हल करना असंभव है।

+0

यह वास्तव में परिपत्र निर्भरता की एक समस्या है। जब आप क्रॉस-आश्रित टाइपिफ, एनम्स, फ़ील्ड्स इत्यादि का उपयोग करने का प्रयास करते हैं तो वही लागू होता है +1 – doc

+0

हर किसी को इस 'क्लोन' समस्या से काटा गया है ... मुझे समाधान के बारे में क्या पसंद नहीं आया है, इसे लपेटने वाला हिस्सा कठिन है, 'typedef' को आगे घोषित नहीं किया जा सकता है और यह दर्द होता है यदि आपके क्लाइंट को पता नहीं है कि अवांछित नाम का उपयोग न करें: / –

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