2011-06-24 24 views
32

मेरे पास निम्न कोड पर एक अजीब स्थिति है। कृपया इसे स्पष्ट करने में मेरी सहायता करें।वर्चुअल फ़ंक्शन डिफ़ॉल्ट तर्क व्यवहार

class B 
{ 
     public: 
      B(); 
      virtual void print(int data=10) 
      { 
        cout << endl << "B--data=" << data; 
      } 
}; 
class D:public B 
{ 
     public: 
      D(); 
      void print(int data=20) 
      { 
        cout << endl << "D--data=" << data; 
      } 
}; 

int main() 
{ 
    B *bp = new D(); 
    bp->print(); 
return 0; 
} 

उत्पादन के बारे में मैं

[ D--data=20 ] 

उम्मीद लेकिन व्यावहारिक में यह

[ D--data=10 ] 

कृपया मदद है। यह आपके लिए स्पष्ट प्रतीत हो सकता है लेकिन मुझे आंतरिक तंत्र से अवगत नहीं है।

+3

एक जवाब आपकी समस्या नहीं सुलझती (या आप यह समझ में आता है), तो कृपया इसे स्वीकार करते हैं, उत्तर के बाईं पर हरे रंग की टिक का उपयोग कर। –

उत्तर

22

डिफ़ॉल्ट तर्क पूरी तरह से संकलित-समय सुविधा हैं। अर्थात। लापता तर्कों के स्थान पर डिफ़ॉल्ट तर्कों का प्रतिस्थापन संकलन समय पर किया जाता है। इस कारण से, जाहिर है, सदस्य फ़ंक्शन के लिए डिफ़ॉल्ट तर्क चयन का कोई तरीका नहीं है गतिशील (यानी रन-टाइम) ऑब्जेक्ट पर निर्भर करता है। यह हमेशा ऑब्जेक्ट के स्थिर (यानी संकलन-समय) प्रकार पर निर्भर करता है।

आपके कोड नमूने में आपके द्वारा लिखे गए कॉल को तुरंत कंप्रेसर द्वारा bp->print(10) के रूप में किसी अन्य चीज़ के बावजूद व्याख्या किया जाता है।

+0

धन्यवाद मेरे संदेह को साफ़ करने के लिए एंड्री। मैंने इस दिशा में नहीं सोचा था। बहुत बहुत धन्यवाद। –

30

मानक कहते हैं (8.3.6.10):

एक आभासी समारोह कॉल (10.3) आभासी समारोह सूचक के स्थिर प्रकार या द्वारा निर्धारित की घोषणा में डिफ़ॉल्ट तर्क का उपयोग करता है संदर्भ ऑब्जेक्ट को दर्शाता है। व्युत्पन्न कक्षा में एक ओवरराइडिंग फ़ंक्शन फ़ंक्शन से ओवरराइड के डिफ़ॉल्ट तर्क प्राप्त नहीं करता है।

इसका मतलब यह है, जब से तुम प्रकार B के सूचक के माध्यम से print बुला रहे हैं, यह B::print के डिफ़ॉल्ट तर्क का उपयोग करता है।

+0

फंडू उत्तर लेकिन समझने में मदद करता है। धन्यवाद –

0

आपका चर प्रकार बी है, इसलिए बी का कार्य कहा जाएगा। डी को कॉल करने के लिए, आपको या तो अपने चर को डी के रूप में घोषित करना होगा, या डी

+0

चूंकि 'प्रिंट' सदस्य फ़ंक्शन वर्चुअल घोषित किया गया है, इसलिए बेस क्लास पॉइंटर के माध्यम से कॉल करने से सदस्य फ़ंक्शन का व्युत्पन्न संस्करण कॉल होगा, न कि मूल संस्करण। – templatetypedef

1

कॉलर की तरफ से डिफ़ॉल्ट तर्क मान पारित किया जाना है। कॉलर व्यूपॉइंट से यह कक्षा बी (डी नहीं) के साथ काम करता है, इसलिए यह 10 (कक्षा बी के लिए)

3

आम तौर पर, उन डिफ़ॉल्ट तर्कों का उपयोग किया जाता है जो एक निश्चित दायरे में दिखाई दे रहे हैं। आप फंकी चीजें (लेकिन नहीं) कर सकते हैं:

#include <iostream> 
void frob (int x) { 
    std::cout << "frob(" << x << ")\n"; 
} 

void frob (int = 0); 
int main() { 
    frob();      // using 0 
    { 
     void frob (int x=5) ; 
     frob();     // using 5 
    } 
    { 
     void frob (int x=-5) ; 
     frob();     // using -5 
    } 
} 

आपके मामले में, बेस क्लास हस्ताक्षर दिखाई देता है। व्युत्पन्न डिफ़ॉल्ट तर्कों का उपयोग करने के लिए, आपको उस फ़ंक्शन को अपने व्युत्पन्न वर्ग में पॉइंटर के माध्यम से स्पष्ट रूप से कॉल करना होगा, या तो इसे इस तरह घोषित करके, या इसे सही तरीके से कास्ट करके।

0

गतिशील बाध्यकारी vpointer और vtable का उपयोग कर रहा है। हालांकि, गतिशील बाध्यकारी केवल फ़ंक्शन पॉइंटर पर लागू होता है। गतिशील बाध्य तर्क के लिए कोई तंत्र नहीं है।

इस प्रकार, डिफ़ॉल्ट तर्क स्थिरता समय पर स्थिर रूप से निर्धारित किया जाता है। इस मामले में, यह स्थिर रूप से बीपी प्रकार द्वारा निर्धारित किया जाता है, जो बेस क्लास के लिए सूचक है।इस प्रकार डेटा = 10 को फंक्शन तर्क के रूप में पास किया जाता है, जबकि फ़ंक्शन पॉइंटर व्युत्पन्न क्लास सदस्य फ़ंक्शन को इंगित कर रहा है: D :: प्रिंट। अनिवार्य रूप से, यह डी :: प्रिंट (10) कहते हैं।

निम्नलिखित कोड स्निपेट और परिणामी आउटपुट स्पष्ट रूप से बिंदु का प्रदर्शन करते हैं: भले ही यह व्युत्पन्न कॉल सदस्य फ़ंक्शन व्युत्पन्न :: आकार बदलें (int) कहता है, यह बेस क्लास डिफ़ॉल्ट तर्क: आकार = 0 पास करता है।

आभासी शून्य व्युत्पन्न :: आकार (int) आकार 0

#include <iostream> 
#include <stdio.h> 
using namespace std; 

#define pr_dbgc(fmt,args...) \ 
    printf("%d %s " fmt "\n",__LINE__,__PRETTY_FUNCTION__, ##args); 

class Base { 
    public: 
     virtual void resize(int size=0){ 
      pr_dbgc("size %d",size); 
     } 
}; 

class Derived : public Base { 
    public: 
     void resize(int size=3){ 
      pr_dbgc("size %d",size); 
     } 
}; 

int main() 
{ 
    Base * base_p = new Base; 
    Derived * derived_p = new Derived; 

    base_p->resize();   /* calling base member function 
            resize with default 
            argument value --- size 0 */ 
    derived_p->resize();  /* calling derived member  
            function resize with default 
            argument default --- size 3 */ 

    base_p = derived_p;   /* dynamic binding using vpointer 
            and vtable */ 
           /* however, this dynamic binding only 
            applied to function pointer. 
            There is no mechanism to dynamic 
            binding argument. */ 
           /* So, the default argument is determined 
            statically by base_p type, 
            which is pointer to base class. Thus 
            size = 0 is passed as function 
            argument */ 

    base_p->resize();   /* polymorphism: calling derived class 
            member function 
            however with base member function 
            default value 0 --- size 0 */ 

    return 0; 
} 


#if 0 
The following shows the outputs: 
17 virtual void Base::resize(int) size 0 
24 virtual void Derived::resize(int) size 3 
24 virtual void Derived::resize(int) size 0 
#endif 
संबंधित मुद्दे