मुझे ये आभासी कक्षाएं एक पुस्तकालय से मिली हैं जो अमूर्त वर्गों के रूप में एक एल्गोरिथ्म को लागू करती हैं

class A{
    public : 
    virtual void foo() = 0 ;
};


class B{
    public:
        void setA(A * a) { m_a = a ;}

        virtual void f() = 0;
        void g() {m_a->foo();}
    protected:
        A * m_a ;
 };

पुस्तकालय का उपयोग करने के लिए आपको केवल कक्षाओं को प्राप्त करना होगा और शुद्ध आभासी कार्यों को लागू करना होगा, जैसे foo(), और कार्यान्वयन के लिए विशिष्ट अन्य विधियां भी प्रदान करें (bar())।

class dA : public A {
    public :
         void foo() {/* ... */}
         void bar() {/* ... */}
};

class dB : public B {
     public :
          void f() ;
};

मैं आम तौर पर कॉल करके इन कक्षाओं का उपयोग करता हूं

dB * mydB = new dB() ;
mydB->setA(new dA() );
mydB->f() ;
mydB->g() ;

लेकिन dB::f() को लागू करते समय मेरे पास एक डिज़ाइन समस्या है, क्योंकि मुझे dA::bar() को कॉल करने की आवश्यकता है जो कि dB के लिए विशिष्ट है। लेकिन कक्षा में, मैं केवल dB trough a B* का संदर्भ रखता हूँ। तब मैंने दो विकल्पों के बारे में सोचा है:

  • एक dynamic_cast का उपयोग करें जब भी f() को B::m_a को dB* में डालने के लिए कहा जाता है
  • dB में एक m_dA सदस्य जोड़ें जो m_a के समान सूचक को संग्रहीत करता है, लेकिन dB विशिष्ट कार्यों तक पहुँचने के लिए उपयोग किया जा सकता है।

बेशक मैं आधार वर्ग नहीं बदल सकता।

मैं जानना चाहता हूं कि इस समस्या का एक और अधिक सुरुचिपूर्ण समाधान है (एक डिजाइन पैटर्न की तरह जिसे मैंने नहीं सोचा था)। यदि नहीं, तो मुझे किसे चुनना चाहिए?

0
Louen 26 जुलाई 2011, 20:13
यदि bar() को बहुत अधिक कॉल किया जाता है तो मैं आपके द्वारा सूचीबद्ध दूसरे विकल्प के साथ जाऊंगा।
 – 
Praetorian
26 जुलाई 2011, 20:22
विज़िटर पैटर्न (en.wikipedia.org/wiki/Visitor_pattern) आपके काम आ सकता है . आपकी समस्या के ऐसे सारगर्भित विवरण के साथ ठोस सिफारिशें देना कठिन है।
 – 
Emile Cormier
26 जुलाई 2011, 20:30
सार्वजनिक विरासत पहली जगह में सही समाधान नहीं हो सकता है... dB इसके उपयोग पर प्रतिबंध लगाता है जो B में मौजूद नहीं है, इसलिए dB का एक उदाहरण सुरक्षित रूप से नहीं हो सकता है B के रूप में माना जाता है।
 – 
Dennis Zickefoose
26 जुलाई 2011, 21:32
: क्या ऐसा मामला होगा जहां निजी विरासत का उपयोग किया जा सकता है?
 – 
Louen
27 जुलाई 2011, 11:58

3 जवाब

सबसे बढ़िया उत्तर

आपके पास तीसरा उपाय है। dB में एक फ़ंक्शन setA() जोड़ें। बेशक, यह फ़ंक्शन B::setA() को छुपाएगा जो कि आपके लिए अच्छा है यदि dB::setA() को इस प्रकार लागू किया जाता है:

class dB : public B 
{
     dA *m_dA ; //add this member also!
     public :
          void f()
          {
             m_dA->bar(); //fast forward : no cast here!
          }
          void setA(A *a) //this hides B::setA()
          {
             m_dA= dynamic_cast<dA*>(a); //just one time dynamic cast!
             if ( m_dA == 0 )
             {  
                 throw std::runtime_error("invalid argument");
             }
             B::setA(a); //now call the hidden function in the base!
          }
};

इस तरह, आपको हर बार dB::f() पर कॉल करने पर डायनामिक_कास्ट करने की आवश्यकता नहीं होती है, जिससे कॉल तेज़ हो जाती है!

2
Nawaz 26 जुलाई 2011, 20:53
लेकिन अगर आपके पास B* b = new dB; है और b->setA(new dA); को कॉल करते हैं, तो गलत फ़ंक्शन को कॉल किया जाएगा, और db::m_dA को ठीक से अपडेट नहीं किया जाएगा।
 – 
Dennis Zickefoose
26 जुलाई 2011, 21:26
@ डेनिस: उस स्थिति में, आपको फ़ंक्शन को dynamic_cast<dB*>(b)->setA(new dA); के रूप में कॉल करना होगा
 – 
Nawaz
26 जुलाई 2011, 21:35
@ डेनिस: हाँ मुझे एहसास हुआ, और इसलिए मेरी टिप्पणी संपादित की। इसे दोबारा पढ़ें।
 – 
Nawaz
26 जुलाई 2011, 21:37

dB एक ठोस वर्ग के रूप में dA पर एक असंबंधित ठोस वर्ग के तरीकों को कॉल नहीं करना चाहिए। यहां तक ​​कि reinterpret_cast के साथ भी यह खराब डिज़ाइन है जो असंबंधित वस्तुओं को जोड़ देता है। सामान्य कार्यक्षमता को एक सामान्य आधार वर्ग या इंटरफ़ेस में रखा जाना चाहिए।

उदाहरण के लिए कक्षा A को एक इंटरफ़ेस माना जा सकता है क्योंकि इसमें शुद्ध आभासी विधियों के अलावा और कुछ नहीं है। इसलिए यदि आप उस इंटरफ़ेस को dB पर भी चाहते हैं तो एकाधिक वंशानुक्रम का उपयोग करना सुरक्षित होगा। उस स्थिति में आपको निश्चित रूप से अपना खुद का foo लागू करना होगा।

class dB : public B, public A {
     public :
          void f();
          void foo();
};

यदि bar() वह है जिसे आप चाहते हैं और किसी कारण से आप इंटरफ़ेस A बदल सकते हैं तो अपना स्वयं का इंटरफ़ेस बनाएं जो एक शुद्ध वर्चुअल फ़ंक्शन प्रदान करता है bar() और फिर दोनों dA और dB आपके नए इंटरफ़ेस से इनहेरिट करते हैं और तदनुसार bar() लागू करते हैं और उसके लिए इंटरफ़ेस पॉइंटर्स का उपयोग करते हैं।

यदि आपको दूसरे के संदर्भ में एक का उपयोग करना चाहिए तो संरचना जाने का रास्ता है लेकिन अस्पष्ट आधार सूचक का नहीं जो गतिशील कलाकारों को विफल कर सकता है। शायद dB के भीतर एक ठोस dA सदस्य बनाएं।

1
AJG85 26 जुलाई 2011, 20:34

आपका dB तभी काम कर सकता है जब उसके पास A वास्तव में dA हो। आपको यह सुनिश्चित करने की ज़रूरत है कि ऐसा हमेशा हो।

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

0
djna 26 जुलाई 2011, 20:24