2012-05-10 27 views
18
class A { 
     int i; 
public: 
     A() {cout<<"in A's def const\n";}; 
     A(int k) {cout<<"In A const\n"; i = k; } 
     }; 

class B : virtual public A { 
public: 
     B(){cout<<"in B's def const\n";}; 
     B(int i) : A(i) {cout<<"in B const\n";} 
     }; 

class C : public B { 
public: 
     C() {cout<<"in C def cstr\n";} 
     C(int i) : B(i) {cout<<"in C const\n";} 
     }; 

int main() 
{ 
     C c(2); 
     return 0; 
} 

इस मामले में उत्पादनआदेश

in A's def const 
in B const 
in C const 

क्यों इस in A const

में प्रवेश नहीं है `यह 1 आर्ग निर्माता कॉल के आदेश का पालन करना चाहिए। लेकिन वर्चुअल कीवर्ड का उपयोग करके बी से ए प्राप्त करने पर वास्तव में क्या हो रहा है।

वहाँ कुछ और सवाल

हैं यहां तक ​​कि अगर मैं उपरोक्त कार्यक्रम में आभासी कीवर्ड निकालकर सभी डिफ़ॉल्ट निर्माता यह त्रुटि देता है हटा दें। तो, इसे डिफ कंस्ट्रक्टर

उत्तर

13

वर्चुअल बेस क्लास के लिए कन्स्ट्रक्टर हमेशा किसी भी तर्क का उपयोग करके सबसे व्युत्पन्न कक्षा से बुलाए जाते हैं। आपके मामले में, सबसे व्युत्पन्न कक्षा प्रारंभकर्ता को निर्दिष्ट नहीं करती है A, इसलिए डिफ़ॉल्ट कन्स्ट्रक्टर का उपयोग किया जाता है।

+1

@james .... आप का कहना है कि सबसे व्युत्पन्न कक्षा यानी सी को ए के लिए प्रारंभकर्ता निर्दिष्ट करना चाहिए, लेकिन एक डिफ़ॉल्ट कन्स्ट्रक्टर को हटाने और सी (int i) जोड़ने पर: ए (i), बी (i) सी निर्माता में यह – Kunal

+0

@MikeDeSimone काम does not ... फिर मैं एक ही लिखा है लेकिन एक के डिफ़ॉल्ट निर्माता हटा दिया, लेकिन मैं संकलन त्रुटि मिलती है ... क्या आप कृपया कर सकते हैं समझाने क्यों इस so..and है कैसे करता है, तो देखभाल करने के लिए मैं इसमें एक जटिल विरासत शामिल है। – Kunal

+0

@ कुनल: हाँ, मैंने अपनी टिप्पणी हटा दी क्योंकि आपने वास्तव में इसे आजमाया था। तो यहां हमारे पास एक जवाब है, वोट दिया गया है, जो काम करने में विफल रहता है। @ जेम्स, कृपया कोड को ठीक करने का तरीका बताएं ताकि 'ए (int)' कन्स्ट्रक्टर को कॉल किया जा सके। –

5

JamesKanze has explained के रूप में, virtual विरासत के मामले में यह वर्चुअल बेस क्लास 'कन्स्ट्रक्टर कहलाता है जो सबसे व्युत्पन्न वर्ग है। इसलिए, यदि आप A के निर्माता को चाहते हैं जो एक पूर्णांक कहलाता है, तो आपको इसे C की प्रारंभिक सूची में जोड़ना होगा।

C(int i) : A(i), B(i) {cout<<"in C const\n";} 

अपने प्रश्न के दूसरे भाग के लिए, डिफ़ॉल्ट कंस्ट्रक्टर्स की आवश्यकता नहीं है, लेकिन फिर व्युत्पन्न वर्ग स्पष्ट रूप से गैर-डिफ़ॉल्ट निर्माता कॉल करना होगा, क्योंकि संकलक एक के अभाव में ऐसा करने के लिए है कि आप के लिए असमर्थ है गैर-डिफ़ॉल्ट कन्स्ट्रक्टर।

#include <iostream> 
using namespace std; 

class A { 
    int i; 
public: 
    // A() {cout<<"in A's def const\n";}; 
    A(int k) {cout<<"In A const\n"; i = k; } 
}; 

class B : virtual public A { 
public: 
    // B(){cout<<"in B's def const\n";}; 
    B(int i) : A(i) {cout<<"in B const\n";} 
}; 

class C : public B { 
public: 
    C() : A(42), B(42) {cout<<"in C def cstr\n";} 
    C(int i) : A(i), B(i) {cout<<"in C const\n";} 
}; 

int main() 
{ 
    C c(2), c2; 
    return 0; 
} 

यह बाहर प्रिंट

In A const 
in B const 
in C const 
In A const 
in B const 
in C def cstr 
+0

@Praetorian ... आपके उत्तर के लिए धन्यवाद। लेकिन फिर भी मैं एक चीज़ के साथ अस्पष्ट हूं .... सी(): ए (42), बी (42) देने के लिए क्यों जरूरी है ?? कृपया – Kunal

+2

@ कुनल प्रत्येक व्युत्पन्न वर्ग कन्स्ट्रक्टर (गैर-पीओडी प्रकारों के लिए) को स्पष्ट करें, इसके बेस क्लास कन्स्ट्रक्टर को प्रारंभ करना होगा। जब आप बेस कन्स्ट्रक्टर को स्पष्ट रूप से सूचीबद्ध नहीं करते हैं, तो संकलक आपके लिए डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल करेगा। यदि ऐसा कोई डिफ़ॉल्ट आधार कन्स्ट्रक्टर मौजूद नहीं है, तो आपको स्पष्ट रूप से मौजूदा बेस कन्स्ट्रक्टर को कॉल करना होगा। – Praetorian

+0

क्या इसका मतलब है ए() को दो बार बुलाया जाएगा? बी() के अंदर ए() को कॉल के साथ क्या होता है? – Youda008

2

वहाँ दो सवाल यहाँ हैं।

क्यों इस एक स्थिरांक में में प्रवेश नहीं कर रहा है?

आप वर्चुअल वंशानुक्रम का उपयोग करते रहे हैं।

जब आप आभासी विरासत का उपयोग करें, Initialization list of most-derived-class's ctor directly invokes the virtual base class's ctor.। इस मामले में, इसका मतलब है कि C का कन्स्ट्रक्टर A का कन्स्ट्रक्टर सीधे पर कॉल करता है। चूंकि आपने C की आरंभिक सूची में कॉल करने के लिए A कन्स्ट्रक्टर निर्दिष्ट नहीं किया है, इसलिए डिफ़ॉल्ट कन्स्ट्रक्टर को कॉल किया जाता है।

यह C::C(int) के अपने कार्यान्वयन को बदलने के द्वारा तय हो गई है:

C(int i) : A(i), B(i) {cout<<"in C const\n";} 

अगर मैं उपरोक्त कार्यक्रम में आभासी कीवर्ड निकालकर सभी डिफ़ॉल्ट निर्माता यह त्रुटि देता है हटा दें। तो, इसे def कन्स्ट्रक्टर की आवश्यकता क्यों है?

क्योंकि B भी निर्दिष्ट नहीं है जो A ctor, कॉल करने के लिए तो डिफ़ॉल्ट निर्माता प्रयोग किया जाता है।यदि आप A एस डीफ़ सीटीआर को हटाते हैं, B संकलित नहीं किया जा सकता है।