2009-09-10 7 views
20

मुझे उम्मीद है कि foo कक्षा D में घोषित किया गया है, लेकिन वर्चुअल चिह्नित नहीं है, तो निम्न कोड fooD में कार्यान्वित करने के लिए कॉल करेगा (चाहे d के गतिशील प्रकार के बावजूद)।सी ++ में, एक फ़ंक्शन स्वचालित रूप से आभासी है यदि यह वर्चुअल फ़ंक्शन को ओवरराइड करता है?

D& d = ...; 
d.foo(); 

हालांकि, निम्नलिखित कार्यक्रम में, ऐसा नहीं है। क्या कोई इसे समझा सकता है? क्या यह विधि स्वचालित रूप से आभासी है यदि यह वर्चुअल फ़ंक्शन को ओवरराइड करता है?

#include <iostream> 

using namespace std; 

class C { 
public: 
     virtual void foo() { cout << "C" << endl; } 
}; 

class D : public C { 
public: 
     void foo() { cout << "D" << endl; } 
}; 

class E : public D { 
public: 
     void foo() { cout << "E" << endl; } 
}; 

int main(int argc, char **argv) 
{ 
     E& e = *new E; 
     D& d = *static_cast<D*>(&e); 
     d.foo(); 
     return 0; 
} 

उपरोक्त कार्यक्रम के उत्पादन में है:

E 
+4

static_cast ज़रूरत से ज़्यादा है - 'डी एंड डी = * static_cast (&e);' 'डी एंड डी = ई के बराबर है, ई */ई से निहित डाली और करने के लिए डी * के कारण'/डी & –

+0

सी ++ में फंक्शन घोषणा में "ओवरराइड" जोड़ने से बेस क्लास फ़ंक्शन को ओवरराइड करने का आपका इरादा स्पष्ट हो जाता है। यह आपके द्वारा घोषित किए गए फ़ंक्शन को बेस से स्थिरता में भिन्न करता है (कुछ ऐसा जो कर सकता है यदि आप std :: अपवाद से उदाहरण प्राप्त करते हैं तो आपको आश्चर्यचकित करें और घोषणा करें कि() गैर-कॉन्स) – Ghita

उत्तर

22

स्टैंडर्ड 10.3.2 (class.virtual) का कहना है:

एक आभासी सदस्य समारोह VF, एक वर्ग बेस में और एक वर्ग के व्युत्पन्न में घोषित किया जाता है, तो बेस, एक सदस्य समारोह VF से प्रत्यक्ष या परोक्ष रूप व्युत्पन्न बेस :: वीएफ घोषित होने के समान नाम और समान पैरामीटर सूची के साथ, व्युत्पन्न :: vf भी वर्चुअल है (चाहे वह घोषित किया गया हो या नहीं) और यह ओवरराइड करता है *

[फुटनोट: एक ही नाम वाला फ़ंक्शन लेकिन वर्चुअल फ़ंक्शन के रूप में एक अलग पैरामीटर सूची (क्लॉज ओवर) आवश्यक रूप से वर्चुअल नहीं है और ओवरराइड नहीं करता है। ओवरराइडिंग फ़ंक्शन की घोषणा में आभासी विनिर्देशक का उपयोग कानूनी है लेकिन अनावश्यक (खाली अर्थशास्त्र है)। ओवरराइडिंग निर्धारित करने में एक्सेस कंट्रोल (क्लॉज क्लास.एसीसी) पर विचार नहीं किया जाता है। --- अंत foonote]

17

त्वरित जवाब नहीं हो सकता है लेकिन सही जवाब है हाँ

सी ++ समारोह छिपने के बारे में पता नहीं है, इसलिए अधिभावी आभासी कीवर्ड वर्चुअल कीवर्ड अंक के बिना वर्चुअल फ़ंक्शन वर्चुअल फ़ंक्शन।

+11

@Yossarian, यही कारण है कि व्युत्पन्न कक्षाओं में आभासी कार्यों को आभासी के रूप में घोषित करने के लिए अच्छा अभ्यास माना जाता है ताकि इरादा स्पष्ट हो। स्कॉट मेयर्स इसकी प्रभावी सी ++ पुस्तक में इसकी चर्चा करता है। –

+0

मैंने कहीं कहीं सुना है कि व्युत्पन्न विधियों में वर्चुअल को चिह्नित नहीं करने से उन्हें लगभग अंतिम बना दिया जाएगा। जो तीसरा स्तर व्युत्पन्न एक गैर वर्चुअल ओवरराइड बनाता है। लेकिन मुझे लगता है कि टेडुज़ के मानक का निकाय इस विश्वास को 'अप्रत्यक्ष रूप से' शब्द के कारण गलत साबित कर रहा है, है ना? –

+2

@ v.oddou "मैंने कहीं सुना है" कि लोगों ने "कहीं कहीं सुना है" आमतौर पर झूठे हैं। ;-) जब तक एक ही हस्ताक्षर वाला कोई फ़ंक्शन पदानुक्रम में 'वर्चुअल' _somewhere_ उच्चतम चिह्नित होता है, तब उसी हस्ताक्षर वाले किसी व्युत्पन्न फ़ंक्शन को ओवरराइड होता है। घोषणा में 'अंतराल' शामिल है या नहीं, 'अंतराल' प्रासंगिक रूप से प्रासंगिक नहीं हैं, फिर भी, कीवर्ड की सबसे मूल उपस्थिति के बाद खाली अर्थशास्त्र है। –

0

आप ई की वस्तु की कोई प्रति नहीं बना रहे हैं और इसे डी में डाल रहे हैं। तो d.foo() सामान्य बहुलक व्यवहार का पालन करता है और व्युत्पन्न वर्ग विधि को कॉल करता है। बेस क्लास में वर्चुअल के रूप में घोषित एक विधि व्युत्पन्न कक्षा में स्वचालित रूप से आभासी हो जाती है।

-1

आउटपुट ("ई") बिल्कुल व्यवहार करता है जैसा कि किसी से व्यवहार करने की अपेक्षा करता है।

कारण: उस संदर्भ का गतिशील (यानी रनटाइम) प्रकार ई है। आप डी को स्थिर अपस्टास्टिंग कर रहे हैं, लेकिन यह पाठ्यक्रम के वास्तविक प्रकार को वास्तविक रूप से नहीं बदलता है।

वर्चुअल विधियों और गतिशील प्रेषणों के पीछे यह बहुत ही विचार है: आप इस प्रकार के मामले में तत्काल, जिस प्रकार आप ई थे, का व्यवहार देखते हैं।