2010-08-22 11 views
5

से सबक्लास में वर्चुअल फ़ंक्शन को कॉल करना मुझे पता है कि यह प्रश्न अंतहीन समय से ढंका हुआ होगा, लेकिन मैंने पिछले प्रश्नों की खोज की है, और कुछ भी पॉप नहीं दिखता है।सुपरक्लास

यह विरासत और वर्चुअल फ़ंक्शंस I C++ के बारे में है। मुझे सुपरक्लास से उप-वर्गों में आभासी कार्यों को कॉल करने में समस्या है।

मुझे एक उदाहरण दें। तीन वर्गों के साथ शुरू करें, जो एक-दूसरे से प्राप्त होते हैं।

class A { 

    void foo() { bar() } 
    virtual void bar() { } 

}; 

class B : public A { 

    virtual void bar() { } 

}; 

class C : public B { 

    virtual void bar() { // do something } 

}; 

अब मैं बी * के रूप में घोषित एक चर होना चाहता हूं लेकिन सी * के रूप में तत्काल होना चाहता हूं।

B* myObject = new C(); 
myObject->foo(); 

जब मैं ऐसा करते हैं, और myObject पर foo फोन(), तो एक :: foo()() बार बुला रहा है। लेकिन केवल बी :: बार() को सी :: बार() नहीं कहा जाता है - जो वास्तव में myObject है, भले ही इसे बी के रूप में घोषित किया गया हो, जो फिर से प्रभावित करता है कि "// कुछ भी नहीं" निष्पादित नहीं होता है।

मैं ए :: foo() कैसे कहूं, कि इसे सबसे कम कार्यान्वयन को देखने की आवश्यकता है?

समझ में आता है?

// Trenskow

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

सी :: फू समस्या नहीं है। कक्षा ए में फू को बुलाया जा रहा है, क्योंकि यह एकमात्र जगह है जिसे इसे लागू किया गया है। समस्या उत्पन्न होती है, जब ए: फू बार() को कॉल करता है। फिर बी: बार को कॉल किया जाता है और सी :: बार नहीं।

हो सकता है कि समस्या है, मेरी कार्यान्वयन में, मैं सिर्फ ए

इस तरह

में वस्तु के लिए एक शून्य * सूचक मिलता है कि:

void A:Foo(void *a) { 

    A* tmpA = static_cast<A*> (a); 
    tmpA->bar(); 

} 

अब संकलक सोचता है, कि tmpA एक है ए। लेकिन किसी भी तरह यह यह समझने का प्रबंधन करता है कि यह बी * है, और बी :: बार कहता है, वास्तव में जब टीएमपीए सी * होता है और इसे सी :: बार को कॉल करना चाहिए।

+1

यदि आपने वास्तविक कोड पोस्ट किया है तो हम बता सकते हैं कि समस्या है। आपको कुछ खास करने की ज़रूरत नहीं है। अगर वाक्यविन्यास त्रुटियों को ठीक किया गया है, तो कोड ('myObject-> foo();') 'सी :: बार() 'कॉल करेगा। – UncleBens

+0

... लेकिन अगर मुझे अनुमान लगाया गया था, तो 'सी' वास्तव में' बार '(एक अलग हस्ताक्षर होने) को ओवरराइड नहीं करता है, या आप ऑब्जेक्ट को कहीं भी टुकड़ा कर रहे हैं (कुछ * * variable = * myObject; ' – UncleBens

+0

मैं अभी भी इसे नहीं खरीदता। सी :: बार() क्यों नहीं कहा जाएगा? क्या आप वास्तविक कोड पोस्ट कर सकते हैं? – EboMike

उत्तर

5

निम्नलिखित प्रिंट "A :: foo C :: bar" अपेक्षित के रूप में। क्या आप कुछ अलग कर रहे हैं? B::bar कभी नहीं कहा जाता है क्योंकि C ऑब्जेक्ट का वास्तविक रनटाइम प्रकार है। C::bar में, आप B::bar पर अपने शरीर में B::bar(); जोड़कर स्पष्ट रूप से कॉल कर सकते हैं।

#include <iostream> 
using namespace std; 

class A { 
public: 
    void foo() { cout << "A::foo "; bar(); } 
    virtual void bar() { } 
}; 

class B : public A { 
public: 
    virtual void bar() { cout << "B::bar" << endl; } 
}; 

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

int main() 
{ 
    B* c = new C(); 
    c->foo(); 
    return 0; 
} 
0

मान लिया जाये कि आप कोड के अपने अंतिम ब्लॉक गलत टाइप और नाम से मेल:

B* variable = new C(); 
variable->foo(); 

फिर सी :: फू विधि कहा जाता है की जा रही है या आप एक बहुत बुरा संकलक का उपयोग कर रहे हैं।

(यह भी मान लिया कि आप वास्तव में सी :: फू में एक संकलक त्रुटि नहीं है, और टिप्पणी वास्तव में std::cout << "Hi mom!" << std::endl; की तरह कुछ है कि)

0

क्या आप इसका मतलब यह नहीं:

B* myObject = new C(); 
myObject->foo(); // not variable->foo() 

class A 
{ 
public: 
    void foo() { bar(); } 
    virtual void bar() { std::cout << "A"; }; 
}; 

class B : public A 
{ 
public: 
    virtual void bar() { std::cout << "B";}; 
}; 

class C : public B 
{ 
public: 
    virtual void bar() { std::cout << "C"; } 
}; 

यह प्रिंट 'सी' अपेक्षित के रूप में।

+0

ओह शूट हाँ। परिवर्तनीय नाम को एक संपादन में बदल दिया है, न केवल इसे चर को कॉल करने के लिए। दूसरी पंक्ति भूल जाना चाहिए। संपादित – Trenskow

0

मैं फ़ॉलो नहीं करता हूं। आप कह रहे हैं

लेकिन केवल बी :: बार() कहा जाता है, नहीं सी :: बार()

नहीं, वर्ग सी के निर्माता लागू, कि vtable जिसका अर्थ है बार() को सी :: बार() पर इंगित करता है, इसलिए इस मामले में foo() को कॉल करना सीधे सी :: बार() पर जाएगा।

आप स्पष्ट रूप से केवल एक के कार्यान्वयन कॉल करने के लिए एक :: foo() बाध्य करना चाहते हैं, तो आप क्या कर सकते हैं कि सिर्फ

लिख कर
void foo() { A::bar(); } 

वास्तव में आप क्या करने की कोशिश कर रहे हैं?

0

आप किस कंपाइलर का उपयोग कर रहे हैं? विजुअल स्टूडियो (आईआईआरसी) में आमतौर पर रनटाइम प्रकार की जानकारी डिफ़ॉल्ट रूप से बंद होती है, तो हो सकता है कि यह बस इतना आसान हो?

2
void A:Foo(void *a) { 

    A* tmpA = static_cast<A*> (a); 
    tmpA->bar(); 

} 

यह अनिर्धारित व्यवहार है। आप बी * को शून्य * पर नहीं डाल सकते हैं, फिर उस शून्य को * ए * पर वापस डालें। यदि आप इसे ठीक से काम करना चाहते हैं, तो आपको शून्य * को हटाना होगा। वैकल्पिक रूप से, आप dynamic_cast को आजमा सकते हैं।

+0

या आप बी * से ए * पहले कास्ट करते हैं और फिर ए * को शून्य * पर कास्ट करते हैं। – Tomek

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