5

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

class Engine 
{ /* Declares pure virtual methods only */ } 

class RunnableEngine : public virtual Engine 
{ /* Defines some of the methods declared in Engine */ } 

class RenderingEngine : public virtual Engine 
{ /* Declares additional pure virtual methods only */ } 

class SimpleOpenGLRenderingEngine : public RunnableEngine, 
    public virtual RenderingEngine 
{ /* Defines the methods declared in Engine and RenderingEngine (that are not 
    already taken care of by RunnableEngine) */ } 

दोनों RunnableEngine और RenderingEngine विस्तार Engine लगभग इतना है कि हीरे की समस्या SimpleOpenGLRenderingEngine प्रभावित नहीं करता।

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

class BobsRenderingEngine : public virtual RenderingEngine 
{ /* Declares additional pure virtual methods only */ } 

class BobsOpenGLRenderingEngine : public SimpleOpenGLRenderingEngine, 
    public BobsRenderingEngine 
{ /* Defines the methods declared in BobsRenderingEngine */ } 

यह संभव नहीं हो अगर मैं SimpleOpenGLRenderingEngine लगभग विस्तार RenderingEngine नहीं बनाया था होगा। मुझे पता है कि बॉब की संभावना यह करने के लिए बहुत कम हो सकती है।

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

+3

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

+2

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

+0

@kids_fok Yup, यह वही है जहां मुझे समस्या है। खैर, मुझे यकीन नहीं है कि आपके प्रश्न में स्पष्ट रूप से 'आईए' को विस्तारित करने के लिए आपको 'बी' की आवश्यकता है, उदाहरण के लिए मेरे प्रश्न में उदाहरण समान है। –

उत्तर

2

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

हालांकि C++ हम एक और तरीका है, वस्तुओं की रचना करने कैप्सूलीकरण है। मुझे लगता है कि नीचे घोषणा काफी आसान समझते हैं और हेरफेर करने के लिए है:

class SimpleOpenGLRenderingEngine 
{ 
public: 
    RunnableEngine& RunEngine() { return _runner; } 
    RenderingEngine& Renderer() { return _renderer; } 

    operator RunnableEngine&() { return _runner; } 
    operator RenderingEngine&() { return _renderer; } 

private: 
    RunnableEngine _runner; 
    RenderingEngine _renderer; 
}; 

यह सच है कि वस्तु आभासी विरासत के साथ अधिक से अधिक स्मृति का उपयोग होगा, लेकिन मुझे शक है वस्तुओं है कि जटिल भारी संख्या में बनाया जाता है।

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

class RunnableEngine : private Engine 
{ 
    Engine& GetEngine() { return *this; } 
    operator Engine&() { return *this; } 
}; 

// Similar implementation for RenderingEngine 

class SimpleOpenGLRenderingEngine : public RunnableEngine, public RenderingEngine 
{ }; 
2

लघु जवाब: हां। आप इसे किसी न किसी।

लांग जवाब: उचित शब्द सार कक्षाएं, नहीं "शुद्ध आभासी कक्षाओं है:

तो, मैं हमेशा विस्तार शुद्ध आभासी कक्षाओं

नोट की परंपरा का उपयोग करके शुरू कर दिया है "।

मैंने हमेशा [सार] वर्गों को विस्तारित करने के सम्मेलन का उपयोग शुरू कर दिया है ताकि उनमें से कई विरासत हीरे की समस्या का कारण न हो।

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

(जावा बल की कमियों आप केवल शुद्ध आभासी कार्य करता है और "इंटरफेस" में कोई डेटा सदस्य डाल करने के लिए, सी ++ और अधिक लचीला, अच्छे के लिए, हमेशा की तरह है।)

सकता है इस कारण के साथ कोई समस्या प्रदर्शन

वर्चुअल-नेस की लागत है।

अपना कोड प्रोफ़ाइल।

क्या इससे [] कार्यक्षमता आदि के साथ कोई समस्या हो सकती है?

संभवतः (शायद ही कभी)।

आप बेस क्लास को अनवरोधित नहीं कर सकते हैं: यदि कुछ विशिष्ट व्युत्पन्न कक्षा में दो अलग-अलग बेस क्लास सबोबजेक्ट्स की आवश्यकता होती है, तो आप दोनों शाखाओं के लिए विरासत का उपयोग नहीं कर सकते हैं, आपको रोकथाम की आवश्यकता है।

1

अच्छा, यह बहुत आसान है। आपने एकल जिम्मेदारी सिद्धांत (एसपीआर) का उल्लंघन किया और यह आपकी समस्या का कारण है। आपका "इंजन" वर्ग एक ईश्वर वर्ग है। एक अच्छी तरह से डिजाइन पदानुक्रम इस समस्या का आह्वान नहीं करता है।

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