5

मुझे एक सदस्य फ़ंक्शन पॉइंटर का उपयोग करने की आवश्यकता है जो कि अन्य कोड में उपयोग की जाने वाली बेस क्लास का तर्क लेता है। खैर, बस मैं नीचे कुछ उदाहरण की तरह [कुछ] करना चाहता हूँ। यह कोड ठीक काम करता है, लेकिन मुझे आश्चर्य है कि ऐसी कास्ट हमेशा सुरक्षित है या नहीं? मैं dynamic या static यहां नहीं डाल सकता।कास्टिंग सदस्य फ़ंक्शन पॉइंटर

#include <cstdio>             

class C 
{               
public:                
     C() : c('c') {}            
     virtual ~C() {}            

     const char c;            
};                 

class D : public C 
{             
public:                
     D() : d('d') {}            
     virtual ~D() {}            

     const char d;            
};                 

class A 
{               
public:                
     A() {}              
     virtual ~A() {}            

     void f(C& c) { printf("%c\n",c.c); }      
     void g(D& d) { printf("%c %c\n",d.c,d.d); }    
};                 

int main (int argc, char const* argv[])        
{                 
     void (A::*pf)(C& c) = &A::f;        
     void (A::*pg)(D& d) = reinterpret_cast<void (A::*)(D&)>(&A::f); 

     A a;               
     C c;               
     D d;               

     (a.*pf)(c);            
     (a.*pg)(d);            

     return 0;             
}                
+3

आप कहते हैं कि कोड ठीक काम करता है, लेकिन यह मेरे लिए भी संकलित नहीं करता है। – Xeo

+1

यह 'reinterpret_cast' के साथ काम करता है और (प्रतीत होता है); मुझे लगता है कि सवाल यह है, क्या यह सुरक्षित है? –

+0

ठंडा यह है कि एफ और जी वास्तव में वर्चुअल हैं? यदि ऐसा है तो आप उन्हें ए से व्युत्पन्न कुछ वर्ग में ओवरराइड कर सकते हैं। –

उत्तर

2

जो आप करने की कोशिश कर रहे हैं वह कानूनी रूप से C++ में नहीं किया जा सकता है। सी ++ फ़ंक्शन पैरामीटर प्रकारों पर किसी भी प्रकार के सह-भिन्नता या अनुबंध-भिन्नता का समर्थन नहीं करता है, भले ही यह सदस्य कार्य या नि: शुल्क फ़ंक्शन है।

अपनी स्थिति में इसे लागू करने के उचित तरीके से किसी भी डाले बिना पैरामीटर प्रकार-रूपांतरण प्रयोजनों के लिए एक मध्यवर्ती समारोह

class A 
{               
public:   
    ...             
    void f(C& c) { printf("%c\n",c.c); }      
    void f_with_D(D& d) { f(d); } 
    ... 
};   

परिचय और है कि मध्यवर्ती कार्य करने के लिए अपने सूचक बिंदु बनाने के लिए है

void (A::*pg)(D& d) = &A::f_with_D; 

अब

A a; 
D d;               
(a.*pg)(d); 

होगा अंततः ca C ऑब्जेक्ट d के उपरोक्त तर्क के रूप में होगा।

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

class A 
{               
public:   
    ...             
    void f(C& c) { printf("%c\n",c.c); }      
    void f(D& d) { f(static_cast<C&>(d)); } 
    ... 
};   

का उपयोग करना होगा ध्यान में रखना है A::f(D&) खुद को बार-बार बुला रहा है।

+0

दुर्भाग्यवश बहुत सारे डीएस कक्षाएं हैं और मैं संकलक को उचित चुनना चाहता हूं।क्या यह फ़ंक्शन अधिभार के साथ काम करेगा? – qba

+0

नहीं यह नहीं होगा। तो निष्कर्ष यह है कि मुझे पूरी तरह से अलग समाधान की आवश्यकता है। – qba

+0

यह काम करता है, धन्यवाद। वर्तमान में केवल टेस्ट कोड में उत्पादन नहीं है, लेकिन एक उम्मीद है :) उत्पादन कोड में मुझे 'त्रुटि: अमान्य static_cast प्रकार से' <अनसुलझा अधिभारित फ़ंक्शन प्रकार> ''मिलता है। शायद कुछ और गड़बड़ है (static_cast लाइब्रेरी द्वारा किया जाता है)। – qba

0

आप इसे काम करने के लिए एक reinterpret_cast उपयोग करने के लिए की जरूरत है। इस मामले में यह सुरक्षित होना चाहिए (टिप्पणियां देखें), लेकिन यदि एकाधिक विरासत का उपयोग किया जाता है तो यह असफल हो सकता है क्योंकि D को C के रूप में पास करते समय पॉइंटर्स को समायोजित करने की आवश्यकता होगी। कंपाइलर को यह पता होना चाहिए कि यह होना चाहिए, जो इस मामले में संभव नहीं है (pg को d के साथ कॉल करना केवल इस चरण को छोड़ देगा, सदस्य फ़ंक्शन को D ऑब्जेक्ट का अनमोड पता मिलेगा)।

टिप्पणियां: मैंने कहा सुरक्षित - ठीक है, वास्तव में यह कारण एक असंबंधित प्रकार के एक प्रकार reinterpret_cast'ing और उस प्रकार का उपयोग करने के लिए अपरिभाषित व्यवहार है, लेकिन यह फिर भी सबसे compilers पर काम करना चाहिए। कृपया, कृपया इसे उत्पादन कोड में न करें।

1

कंपाइलर को आपके द्वारा लिखे गए गतिशील_कास्ट के साथ कोड को अस्वीकार कर देना चाहिए। (मुझे लगता है कि यह एक टाइपो था और आपका मतलब आपके परिचय टेक्स्ट पर विचार करने के लिए एक reinterpret_cast था)।

reinterpret_cast के साथ, आप अच्छी तरह से परिभाषित मामलों में से एक में नहीं हैं (जो अधिकतर किसी अन्य प्रकार में परिवर्तित हो जाते हैं और फिर मूल पर वापस आते हैं)। तो हम कास्ट के परिणाम के लिए अनिश्चित क्षेत्र में हैं, और कलाकार के लिए अनिश्चित एक में जब कलाकार का परिणाम बुलाते हैं।

1

नहीं, आपका उदाहरण ठीक काम नहीं करता है।
सबसे पहले, आप केवल का उपयोग संबंधित कक्षा-प्रकार के बीच डालने के लिए कर सकते हैं, कुछ और नहीं।
दूसरा, भले ही आप की जगह है कि एक reinterpret_cast या सी शैली कलाकारों के साथ dynamic_cast (जो मुझे लगता है आप का मतलब है), तो मैं निम्नलिखित उत्पादन प्राप्त करें:

c
c

नहीं वास्तव में क्या आप चाहते थे।

क्यों काम करता है और बहुत दुर्घटनाग्रस्त नहीं होता है क्योंकि यह सदस्य-कार्य-पॉइंटर्स के बीच आगे और आगे बढ़ने के लिए "सुरक्षित" है, कोई जानकारी खो जाएगी नहीं।
यह अभी भी कुछ प्रिंट क्यों करता है क्योंकि संकलक प्रकारों के साथ कोई त्रुटि नहीं देखता है, लेकिन असेंबली प्रकारों की परवाह नहीं करता है, यह केवल पते के बारे में परवाह करता है, इसलिए यह अभी भी A::f पर कॉल करेगा, क्योंकि यह वह सूचक है जिसे आपने सहेजा है, भले ही प्रकार का

दिलचस्प है, यह अभी भी भले ही आप कक्षाएं unrelate (DC से विरासत नहीं है), फिर से, क्योंकि विधानसभा प्रकार के बारे में परवाह नहीं है काम करता है। निम्नलिखित तरीके से एक में कार्यों को बदलना:

void f(C& c) { printf("f(C& c): %c\n",c.c); } 
void g(D& d) { printf("g(D& d): %c\n",d.d); } 

निम्नलिखित उत्पादन की ओर जाता है:

f(C& c): c
f(C& c): d

"? यह कैसे काम करता है D भी एक c सदस्य नहीं है!"। ठीक है, फिर पते के कारण। दोनों चर this सूचक, अर्थात् +0 से उसी ऑफ़सेट पर हैं।अब C (कक्षा सरलीकृत) में किसी अन्य सदस्य डाल देता है:

struct C{ 
     C() : c('c') {} 
     int i; // mean 
     const char c; 
}; 

और वह फिर से कोशिश, उत्पादन:

f(C& c): c
f(C& c): ╠

हाँ, वहाँ हम चले। C::c अब ऑफ़सेट +4 (+0 + sizeof int) पर है, और printf वहां से पढ़ता है। D में, ऐसी कोई ऑफसेट नहीं है और printf अनियमित स्मृति से पढ़ता है। दूसरी ओर, अनियमित स्मृति तक पहुंच अपरिभाषित व्यवहार है।

तो अंत में निष्कर्ष पर आना: नहीं, यह सुरक्षित नहीं है। :)

+0

ठीक है, reinterpret_cast का परिणाम वास्तव में क्या चाहता है। पीजी फंक्शन फंक्शन करने के लिए सूचक है, इसलिए इसे फंक्शन एफ कॉल करना चाहिए। यह और क्या हो सकता है? – qba

+0

@qba: फिर आपने इसे 'pg' क्यों कहा और आपके' ए' में 'g' फ़ंक्शन है? यदि आप फ़ंक्शन 'एफ' कहलाते हैं, तो आपने अपने उदाहरण कोड में 'g' क्यों शामिल किया? – Xeo

+0

एक और उदाहरण कॉपी और पेस्ट कितना खराब है: पी मैं उन कार्यों के साथ सी ++ का परीक्षण कर रहा था, और मैं 'g' को हटाने के लिए भूल गया। – qba