2008-10-31 6 views
22

मेरे पास एक सार आधार वर्ग है जो एक इंटरफ़ेस के रूप में कार्य करता है।दो व्युत्पन्न कक्षाओं से एकाधिक विरासत

मेरे पास व्युत्पन्न कक्षाओं के दो "सेट" हैं, जो अमूर्त वर्ग के आधे हिस्से को लागू करते हैं। (एक "सेट" प्रारंभिक से संबंधित अमूर्त वर्चुअल विधियों को परिभाषित करता है, अन्य "सेट" वास्तविक "काम" से संबंधित लोगों को परिभाषित करता है।)

तब मैंने कक्षाएं ली हैं जो पूरी तरह परिभाषित कक्षाओं (और कुछ भी खुद को जोड़ता नहीं है)।

तो: (बुरा स्यूडोकोड)

class AbsBase { 
    virtual void init() = 0; 
    virtual void work() = 0; 
} 

class AbsInit : public AbsBase { 
    void init() { do_this(); } 
    // work() still abs 
} 

class AbsWork : public AbsBase { 
    void work() { do_this(); } 
    // init() still abs 
} 

class NotAbsTotal : public AbsInit, public AbsWork { 
    // Nothing, both should be defined 
} 

सबसे पहले, मैं यह कर सकता है? क्या मैं दो वर्गों से प्राप्त कर सकता हूं जो दोनों एक ही आधार से व्युत्पन्न हैं? (मुझे ऐसी ही उम्मीद है)।

यहां "असली समस्या" है, हालांकि (मैंने उदाहरण को सरल बनाने के लिए थोड़ा ऊपर झूठ बोला)।

class AbsBase { 
public: 
    void init() { init_impl(); } 
    void work() { work_impl(); } 

private: 
    virtual void init_impl() = 0; 
    virtual void work_impl() = 0; 
} 

वजह से, एक आम मुहावरा सभी आभासी तरीकों निजी बनाने के लिए है:

क्या मैं सच में चला गया और किया है आधार वर्ग के लिए गैर सार accessors विधियों को जोड़ने है।

दुर्भाग्यवश, अब अब AbsInit, और AbsWork दोनों इन तरीकों का उत्तराधिकारी हैं, और इसलिए NotAbsTotal को "प्रत्येक में से दो" प्राप्त होता है (मुझे एहसास है कि मैं संकलन समय पर वास्तव में क्या हो रहा है)।

वैसे भी, g ++ शिकायत करता है कि: "वर्ग का उपयोग करने का प्रयास करते समय सदस्य init() अस्पष्ट है"।

मुझे लगता है कि, मैंने अपने एब्सबेस वर्ग को शुद्ध इंटरफ़ेस के रूप में उपयोग किया था, यह टालना होगा (माना जाता है कि शीर्ष उदाहरण मान्य है)।

तो: - क्या मैं अपने कार्यान्वयन के साथ बंद हूं? - क्या यह आभासी तरीकों को निजी बनाने के मुहावरे की सीमा है? - मैं जो चाहता हूं उसे करने के लिए अपने कोड को दोबारा कैसे दोहरा सकता हूं? (एक आम इंटरफ़ेस एक तरह से सदस्य कार्यों के "सेट" के लिए कार्यान्वयन बाहर स्वैप करने के लिए प्रदान करें, लेकिन अनुमति देते हैं)

संपादित करें:

लगता है मैं पहले एक नहीं कर रहा हूँ: http://en.wikipedia.org/wiki/Diamond_problem

लगता आभासी विरासत है यहां समाधान मैंने पहले आभासी विरासत के बारे में सुना है, लेकिन मैंने इसके चारों ओर अपना सिर लपेटा नहीं है। मैं अभी भी सुझावों के लिए खुला हूं।

उत्तर

33

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


class AbsBase {...}; 
class AbsInit: public virtual AbsBase {...}; 
class AbsWork: public virtual AbsBase {...}; 
class NotAbsTotal: public AbsInit, public AbsWork {...}; 

असल में, डिफ़ॉल्ट, गैर आभासी एकाधिक वंशानुक्रम की एक प्रति प्रत्येक आधार वर्ग में शामिल होंगे व्युत्पन्न वर्ग, और उनके सभी तरीकों को शामिल करता है। यही कारण है कि आपके पास AbsBase की दो प्रतियां हैं - और आपकी विधि का उपयोग संदिग्ध है क्योंकि विधियों के दोनों सेट लोड हो गए हैं, इसलिए C++ को यह जानने का कोई तरीका नहीं है कि कौन सी प्रति एक्सेस हो!

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

+0

आप ऐसा क्यों कहते हैं? आभासी विरासत की वाक्यविन्यास जटिलता के अलावा, क्या प्रभाव हैं? – mmocny

+0

किसी व्युत्पन्न कक्षा में आधार सूचक का रूपांतरण आमतौर पर गतिशील लुकअप तालिका का उपयोग करके सूचक समायोजन शामिल करता है। यह अतिरिक्त संकेतक आधार से व्युत्पन्न करने की लागत को प्रस्तुत करता है। वर्चुअल विधि को कॉल करते समय, यह ओवरहेड कॉल के शोर में होता है। –

1

यह किया जा सकता है, हालांकि यह अधिकतर शावर देता है।

NotAbsTotal::work() 
{ 
    AbsInit::work_impl(); 
} 

(सही के साथ अद्यतन:

आप "आभासी विरासत" का उपयोग करने की जरूरत है, वाक्य रचना है जिसके लिए जो कार्य करते हैं आप उपयोग करना चाहते निर्दिष्ट करने के लिए की तरह

class AbsInit: public virtual AbsBase {...}; 
class AbsWork: public virtual AbsBase {...}; 
class NotAbsTotal: public AbsInit, public AbsWork {...}; 

तो आपके पास कुछ है सिंटेक्स)

1

आप वर्चुअल रूप में विरासत घोषित करने के लिए की जरूरत है:

struct AbsBase { 
      virtual void init() = 0; 
      virtual void work() = 0; 
}; 

struct AbsInit : virtual public AbsBase { 
      void init() { } 
}; 

struct AbsWork : virtual public AbsBase { 
      void work() { } 
}; 

struct NotAbsTotal : virtual public AbsInit, virtual public AbsWork { 
}; 

void f(NotAbsTotal *p) 
{ 
     p->init(); 
} 

NotAbsTotal x; 
+0

यह अच्छी तरह से बाहर काम किया, यहां तक ​​कि मेरी गैर आभासी सार्वजनिक तरीकों के साथ। हालांकि, मुझे यह देखने की कोशिश करनी होगी कि बेस प्रकार के सूचक को व्युत्पन्न प्रकार के ऑब्जेक्ट का उपयोग करते समय क्या होता है, यह सुनिश्चित करने के लिए कि आभासी विरासत वर्चुअल फ़ंक्शन ओवरलोडिंग की तरह काम करती है :) – mmocny

+0

वर्चुअल बेस से व्युत्पन्न कक्षा में कनवर्ट करते समय, आप हमेशा dynamic_cast <> का उपयोग करने की आवश्यकता होती है, जिसके बदले में आभासी आधार वर्चुअल बेस में परिभाषित किया जाता है।आभासी आधार के सादा उपयोग में कोई समस्या नहीं होनी चाहिए - यह व्युत्पन्न रूप से व्युत्पन्न वर्ग तक पहुंच प्रदान करेगी। –

0

आपको यहां मॉडल करने की कोशिश करने की शर्तों के बारे में सोचना शुरू करना होगा।

सार्वजनिक विरासत का उपयोग कभी भी "आईएसए" रिश्ते को मॉडल करने के लिए किया जाना चाहिए, उदाहरण के लिए एक कुत्ता एक जानवर है, एक वर्ग एक आकार है, आदि

ओओ डिजाइन के विभिन्न पहलुओं के बारे में एक उत्कृष्ट निबंध के लिए स्कॉट मेयर की पुस्तक प्रभावी सी ++ पर एक नज़र डालें।

संपादित करें: मैं यह कहना भूल गया था कि अब तक दिए गए उत्तरों तकनीकी रूप से सही हैं, लेकिन मुझे नहीं लगता कि उनमें से कोई भी मॉडल के मॉडल की कोशिश कर रहे मुद्दों के मुद्दों को संबोधित करता है और यह आपकी समस्या का क्रूक्स है!

HTH

चियर्स,

रोब

0

मैं नीचे दिए गए लिंक पर एक अच्छा और सरल उदाहरण मिल गया। लेख आयत के क्षेत्र और परिधि की गणना के लिए एक उदाहरण कार्यक्रम के साथ बताता है। आप इसे देख सकते हैं .. चेयर

बहुस्तरीय विरासत एक विरासत पदानुक्रम है जिसमें एक व्युत्पन्न कक्षा कई बेस क्लास से प्राप्त होती है। और पढ़ें ..

http://www.mobihackman.in/2013/09/multiple-inheritance-example.html