2012-08-10 24 views
5

के लिए इस कोड को देखते हैं:कैसे आधार वर्ग सूचक के माध्यम से व्युत्पन्न वर्ग की आभासी समारोह कॉल करने के लिए

class CBase 
{ 
public: 
    virtual vfunc() { cout << "CBase::vfunc()" << endl; } 
}; 

class CChild: public CBase 
{ 
public: 
    vfunc() { cout << "CChild::vfunc()" << endl; } 
}; 

int main() 
{ 
CBase *pBase = new CBase; 
((CChild*)pBase)->vfunc(); // !!! important 
delete pBase; 
return 0; 
} 

उत्पादन होता है:

CBase::vfunc() 

लेकिन मैं देखना चाहता हूँ: CChild :: vfunc()

स्पष्ट ((सीसीएचल्ड *) पीबीएएस) "सीसीएचल्ड *" टाइप करने के लिए उत्सुक है। तो व्युत्पन्न vfunc() को कॉल करने के लिए मुझे "महत्वपूर्ण" स्ट्रिंग को प्रतिस्थापित करने की आवश्यकता क्यों है: ((CChild *) pBase) -> CChild :: vfunc();

उत्तर

6

यही नहीं यह कैसे काम करता है - यह है:

CBase *pBase = new CChild; 
pBase->vfunc(); 

virtual फ़ंक्शन कॉल संकेत पर गतिशील रूप से हल कर रहे हैं & संदर्भ (जब तक आप विधि स्पष्ट रूप से कहते हैं, जैसे तुमने किया था)। जिसका अर्थ यह है कि इससे कोई फर्क नहीं पड़ता कि आप पॉइंटर के कंपाइलर को क्या कहते हैं, यह vftable में विधि की तलाश करेगा। जो, आपके मामले में, vftableCBase है।

5

आप नहीं कर सकते। *pBaseCBase प्रकार का एक ऑब्जेक्ट है। आप इसका इलाज नहीं कर सकते जैसे कि यह CChild था क्योंकि यह CChild ऑब्जेक्ट नहीं है।

कास्ट द्वारा प्राप्त पॉइंटर का उपयोग CChild* पर आपके प्रोग्राम को अपरिभाषित व्यवहार प्रदर्शित करने का कारण बनता है।

+1

तो Schildt H को कैसे समझें: "बेस बेस पॉइंटर को उस आधार से प्राप्त किसी भी वर्ग के किसी ऑब्जेक्ट के लिए पॉइंटर के रूप में भी उपयोग किया जा सकता है"। – LEXX

+0

और इसलिए स्ट्रिंग ((CChild *) pBase क्यों) -> CChild :: vfunc() काम करता है? – LEXX

+0

@LEXX: सबसे पहले, आपको उस पुस्तक को जला देना चाहिए और [एक अच्छी प्रारंभिक पुस्तक] प्राप्त करना चाहिए (http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)। वह उद्धरण में जो कहता है वह सही है, यद्यपि। बेस क्लास पॉइंटर ('सीबीएएस *') 'सीबीएसई' (जैसे 'सीसीएचल्ड') से व्युत्पन्न प्रकार के किसी ऑब्जेक्ट को इंगित कर सकता है।ऐसा नहीं है कि आपने क्या किया है, यद्यपि: आपका बेस क्लास पॉइंटर बेस क्लास ऑब्जेक्ट को इंगित करता है। यदि आपके पास, उदाहरण के लिए, 'सीबीज़ * पी = नया सीसीएचआईल्ड();', तो 'पी 'एक व्युत्पन्न वर्ग की वस्तु को इंगित करने वाला बेस क्लास पॉइंटर होगा। –

2

अन्य उत्तरों महत्वपूर्ण अंक बनाते हैं - पूरक के लिए: यदि आप वास्तव में CChild से निपट रहे हैं (उदाहरण के लिए यह एक पैरामीटर के रूप में पारित संदर्भ है), तो आप डाउनकास्ट के लिए dynamic_cast का उपयोग कर सकते हैं। हालांकि, dynamic_cast पर उच्च निर्भरता अक्सर संकेत है कि आपका डिज़ाइन गलत हो गया है।

डाली पर विस्तार यहां पाया जा सकता: http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx

इसलिए प्रक्रिया dynamic_cast के माध्यम से कास्टिंग CChild करने के लिए CBase पैरामीटर, संदर्भ है अगर करना पड़ेगा एक CChild और dynamic_cast सफल होता है, तो आप यकीन है कि आप कर रहे हैं हो सकता है CChild से निपटने और फिर आप इसे CChild के रूप में सुरक्षित रूप से उपयोग कर सकते हैं।

0

यहां समस्या बहुत सरल लगती है। सीबीएसई जादुई रूप से सीसीएचल्ड में अपग्रेड नहीं कर सकता! मुझे अपना उदाहरण दोबारा लिखने दें और कुछ टिप्पणियां जोड़ें। यह आत्म व्याख्यात्मक होना चाहिए ...

#include <iostream> 

class CBase { 
public: 
    virtual void vfunc() { std::cout << "CBase::vfunc()" << std::endl; } 
    virtual ~CBase(){} // Virtual destructor... extremely important! I'll let you figure out why as an excercise 
}; 

class CChild: public CBase { 
public: 
    void vfunc() { std::cout << "CChild::vfunc()" << std::endl; } 
    ~CChild(){} // Is this destructor called? When? Try adding some std::cout to each destructor 
}; 

int main() 
{ 
    CBase *ptr1 = new CBase; 
    CBase *ptr2 = new CChild; 

    ptr1->vfunc(); // ptr1 points to an instance of CBase. This is what's important!! 
    ptr2->vfunc(); // ptr2 points to an instance of CChild, which can be referenced to as a CBase 

    delete ptr1; 
    delete ptr2; 
} 

आउटपुट:

CBase::vfunc() 
CChild::vfunc() 

पुनश्च: मैं सिर्फ महसूस किया कि मैं पार्टी के लिए के बारे में 5 साल देर हो रही है, लेकिन जब से मैं इस पर मैं शैक्षिक मूल्य खोजने के ' वैसे भी इसे पोस्ट करेंगे!

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