2017-12-26 66 views
6

से कार्य करने के लिए पॉइंटर द्वारा कॉल बेस वर्चुअल विधि कॉल करने के लिए मुझे मूल विधि ए :: foo() को पॉइंटर द्वारा व्युत्पन्न कक्षा से कॉल करने की आवश्यकता है।व्युत्पन्न वर्ग

#include <iostream> 
struct A{ 
    virtual void foo() { std::cout << "A::foo()" << std::endl; } 
}; 

struct B:A{ 
    virtual void foo() { std::cout << "B::foo()" << std::endl; } 
    void callBase(void (A::*f)()){ 
     (this->*f)(); 
    } 
}; 

int main(){ 
    B* p=new B(); 
    p->callBase(&A::foo); 
} 

यह कोड आउटपुट "बी :: foo"। क्या पॉइंटर द्वारा विधि में ए :: foo() को कॉल करना संभव है?

+0

मुझे नहीं लगता कि आप कर सकते हैं। हालांकि, मैं अतीत में गलत रहा हूं :) आइए आशा करते हैं कि किसी से ज्यादा जानकार मुझे एक रास्ता जानता है। –

+1

आप इसे सीधे 'p-> ए :: foo();' पर कॉल कर सकते हैं, लेकिन सदस्य फ़ंक्शन के लिए पॉइंटर के माध्यम से नहीं (जो मुझे लगता है कि आभासी कार्यों का बिंदु है)। –

+0

मेरा मानना ​​है कि आप इस काम को गैर-आभासी 'बार' रखते हुए काम करते हैं जो काम करता है, और 'बार' के लिए 'foo' प्रतिनिधि' है, 'कॉलबेस' फिर 'बार' कहता है। यह अधिक तार्किक है क्योंकि बहुरूपता का अर्थ है 'बी' को हमेशा अपना' foo' –

उत्तर

1

ठीक है, आप this के मान को ओवरराइट करने के साथ कुछ चाल का उपयोग कर कुछ ऐसा कर सकते हैं। आपको शायद ऐसा करने की कोशिश नहीं करनी चाहिए, हालांकि vtable पॉइंटर्स हाथ से संशोधित करने के लिए नहीं हैं।

आपके द्वारा वर्णित करने के लिए, हमें सूचकांक को vtable पर रखना होगा। हमारी ऑब्जेक्ट p में बी के vtable के लिए केवल पॉइंटर है, इसलिए हमें ए के कन्स्ट्रक्टर के भीतर किसी फ़ील्ड में दूसरा पॉइंटर स्टोर करना होगा।

#include <iostream> 
struct A{ 
    virtual void foo() { std::cout << "A::foo()" << std::endl; } 
    int *a_vtable_ptr; 
    // First, save value of A's vtable pointer in a separate variable. 
    A() { a_vtable_ptr = *(int**)this; } 
}; 

struct B:A{ 
    virtual void foo() { std::cout << "B::foo()" << std::endl; } 
    void callBase(void (A::*f)()){ 
     int *my_vtable_ptr = *(int**)this; 
     // Then modify vtable pointer of given object to one that corresponds to class A. 
     *(int**)this = a_vtable_ptr; 
     (this->*f)(); // Call the method as usual. 
     // Restore the original vtable pointer. 
     *(int**)this = my_vtable_ptr; 
    } 
}; 

// Function main() is not modified. 
int main(){ 
    B* p=new B(); 
    void (A::*f)() = &A::foo; 
    p->callBase(f); 
} 

आउटपुट::

A::foo() 

Process finished with exit code 0 
1

आभासी तरीकों आभासी तरीकों की बहुरूपता और संकेत लागू करने के लिए तैयार कर रहे हैं उनके बहुरूपी व्यवहार का समर्थन करता है

यहाँ कोड है। लेकिन आपने स्पष्ट रूप से p->A::foo() पर कॉल करके आधार विधि को कॉल करने की संभावना दी है।

तो यदि आप पॉइंटर द्वारा आधार विधि को कॉल करना चाहते हैं, तो आपको इसे गैर-आभासी बनाना चाहिए (जैसा कि @PasserBy टिप्पणियों में उल्लिखित है)।

कोड उदाहरण:

struct A { 
    virtual void foo() { std::cout << "A::foo()" << std::endl; } 
    void bar() { std::cout << "A::bar()" << std::endl; } 
    void callBase(void (A::*f)()) { (this->*f)(); } 
}; 

struct B : A { 
    virtual void foo() { std::cout << "B::foo()" << std::endl; } 
    void bar() { std::cout << "B::bar()" << std::endl; } 
}; 

int main() 
{ 
    A* p = new B(); 
    p->foo(); 
    p->bar(); 
    p->callBase(&A::foo); 
    p->callBase(&A::bar); 
    p->A::foo(); 
    p->A::bar(); 
} 

आउटपुट:

B::foo() 
A::bar() 
B::foo() 
A::bar() 
A::foo() 
A::bar() 
संबंधित मुद्दे