2014-09-08 12 views
5

निम्नलिखित कोड पर विचार करें:शुद्ध आभासी समारोह कॉल दिलचस्प मामलों

#include <iostream> 
using namespace std; 

class A 
{ 
    public: 
    virtual void f() = 0; 
    A(){f();} 
}; 

void A::f() { 
    cout<<"A"<<endl; 
} 

class B:public A{ 
public: 
    void f(){cout<<"B"<<endl;} 
}; 
int main() 
{ 
B b; 
} 

इस मामले में मैं सीधे निर्माता से आभासी फ़ंक्शन को कॉल करें और संकलक चेतावनी जो कहते हैं मिलती है:
चेतावनी: सार आभासी 'आभासी शून्य एक: : एफ() 'कन्स्ट्रक्टर से बुलाया जाता है।
लेकिन यह बिना समाप्ति और प्रिंट ए

निष्पादित करता है, तो मैं इस तरह समारोह के कॉल लपेट:

class A 
{ 
    public: 
    virtual void f() = 0; 
    A(){g();} 
    void g(){f();} 
}; 

void A::f(){cout<<"A"<<endl;} 

class B:public A{ 
public: 
    void f(){cout<<"B"<<endl;} 
}; 
int main() 
{ 
B b; 
} 

संकलक संकलन के दौरान नहीं उत्पादन किसी चेतावनी करता है, लेकिन यह निम्नलिखित के साथ रनटाइम पर कुचल संदेश:

pure virtual method called 
terminate called without active exception 
Abort 

क्या कोई इन दोनों मामलों के व्यवहार की व्याख्या कर सकता है?

+0

संकेत: http://stackoverflow.com/questions/962132/calling-virtual-functions-inside-constructors – dragosht

उत्तर

1

§ 10.4 सार कक्षाएं [class.abstract]/p6

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

संक्षेप में: वस्तु के लिए प्रत्यक्ष या परोक्ष रूप से एक शुद्ध आभासी समारोह के लिए कॉल करने के प्रभाव निर्माता से बनाया जा रहा अनिर्धारित रहता है।

शुद्ध आभासी सदस्य कार्यों के लिए एक कॉल, एक निर्माता या एक नाशक, कोई फर्क नहीं पड़ता अगर कॉल प्रत्यक्ष या अप्रत्यक्ष रूप से नहीं किया जा सकता क्योंकि तब आप एक अपरिभाषित व्यवहार अंत।

एक शुद्ध आभासी समारोह के कार्यान्वयन प्रदान करने का ही उपयोगी उदाहरण है जब यह एक व्युत्पन्न वर्ग से फोन:

struct A 
{ 
    virtual void f() = 0; 
}; 

void A::f() 
{ 
    cout<<"A"<<endl; 
} 

struct B : A 
{ 
    void f() 
    { 
     A::f(); 
     cout<<"B"<<endl; 
    } 
}; 
1

पहले मामले में, संकलक आपको A::f() पर स्थाई रूप से प्रेषित करके सहेजने के लिए होता है, क्योंकि यह स्थिर प्रकार A जानता है। लेकिन यह बिल्कुल सही है कि यह बेहद अपरिभाषित व्यवहार है और आपको यह नहीं करना चाहिए।

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

0

Undefined व्यवहार का मतलब संकलक में किसी भी विशेष रूप से परिभाषित स्थिति से निपटने की जरूरत नहीं है कि तौर तरीका।

यहां आपके कंपाइलर, जो कि अपने कन्स्ट्रक्टर में वास्तविक प्रकार के ए को जानता था, उसे वी-टेबल के माध्यम से कॉल करने के बजाय शुद्ध आभासी विधि में रेखांकित करने में सक्षम था। यह तब होगा जब विधि सामान्य आभासी थी, शुद्ध वर्चुअल नहीं, और यह परिभाषित व्यवहार होगा।

जबकि यह g() के माध्यम से भी व्यवहार होगा, संकलक ने शुद्ध वर्चुअल f() फ़ंक्शन के लिए ऐसा नहीं किया है। यह करने की ज़रूरत नहीं है।

सरल नैतिक अपरिभाषित व्यवहार का आह्वान नहीं करता है, और यदि आप कन्स्ट्रक्टर से f() पर कॉल करना चाहते हैं तो इसे शुद्ध वर्चुअल न बनाएं।

यदि आप f() को लागू करने के लिए अपने उप-वर्गों को लागू करना चाहते हैं, तो इसे ए के निर्माता से कॉल न करें, लेकिन वह फ़ंक्शन दें जिसे आप एक अलग नाम कॉल करना चाहते हैं। पसंदीदा रूप से वर्चुअल नहीं।

1

देखने के एक संकलक के दृष्टिकोण से, अगर आप कैसे समारोह च() शुरू हो जाती है पर नज़र डालें:

  • केस -1: एक के ctor कॉल ए-ctor => च() सीधे। कंपाइलर ठीक से जानता है कि यह मामला है और चेतावनी जारी करने का फैसला करता है।
  • केस -2: ए का सीटीआर कॉल ए-सीटीआर => जी() => एफ()। कक्षा विधियों में से किसी एक को कॉल() को कॉल करने के पूरी तरह से वैध मामले हैं। कंपाइलर यह नहीं कह सकता कि यह अवैध है। कॉलग्राफ * => बार() => g() -> f() से हो सकता है, जिसका अर्थ है कि ऑब्जेक्ट का प्रकार ज्ञात नहीं है। इस तरह के पथ संभव है, गतिशील प्रेषण आवश्यक बनाता है - रनटाइम त्रुटि के लिए अग्रणी।

जैसा कि अन्य ने बताया, यह अनिर्धारित उपयोग है और संकलक केवल पहचान और चेतावनी में जाते हैं।

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